suppressPackageStartupMessages({
  library(tidyverse)
  library(irlba)
  library(DropletUtils)
  library(scater)
  library(scran)
  library(Seurat) ## just 4 loading the object
  library(SingleCellExperiment)
  library(miloR)
  library(patchwork)
  library(igraph)
  })
There were 24 warnings (use warnings() to see them)

Using data from Ramachandran et al. 2019 (GEO accessiion: GSE136103). The Seurat object was downloaded from https://datashare.is.ed.ac.uk/handle/10283/3433, upon request to the authors.

load("/nfs/team205/ed6/data/Ramachandran2019_liver/tissue.rdata")
## Convert to SingleCellExperiment
liver_sce <- SingleCellExperiment(assay = list(counts=tissue@raw.data, logcounts=tissue@data), 
                                  colData = tissue@meta.data)

Feature selection

dec_liver <- modelGeneVar(liver_sce)

# Visualizing the fit:
fit_liver <- metadata(dec_liver)
plot(fit_liver$mean, fit_liver$var, xlab="Mean of log-expression",
    ylab="Variance of log-expression")


hvgs <- getTopHVGs(dec_liver, n=3000)

Dim reduction

liver_sce <- runPCA(liver_sce, subset_row=hvgs, ncomponents=11)

plotPCA(liver_sce, colour_by="condition", ncomponents=3)

scater::plotUMAP(liver_sce, colour_by="condition", point_alpha=1,  point_size=0.5) 
Error in reducedDimNames(object) : object 'liver_sce' not found

Apply Milo

Let’s test for differential abundance between healthy and cirrhotic livers.

Sample neighbourhoods

Make design matrix

liver_meta <- as.tibble(colData(liver_milo)[,c("dataset","condition")]) 
`as.tibble()` is deprecated as of tibble 2.0.0.
Please use `as_tibble()` instead.
The signature and semantics have changed, see `?as_tibble`.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
liver_meta <- distinct(liver_meta) %>%
  mutate(condition=factor(condition, levels=c("Uninjured", "Cirrhotic"))) %>%
  column_to_rownames("dataset")

Test DA

## Save milo object and results
saveRDS(liver_milo,"/nfs/team205/ed6/data/Ramachandran2019_liver/tissue_milo.RDS")
write_csv(milo_res, "/nfs/team205/ed6/data/Ramachandran2019_liver/milo_results.csv")
liver_milo <- readRDS("/nfs/team205/ed6/data/Ramachandran2019_liver/tissue_milo.RDS")
milo_res <- read_csv("/nfs/team205/ed6/data/Ramachandran2019_liver/milo_results.csv")
Parsed with column specification:
cols(
  logFC = col_double(),
  logCPM = col_double(),
  F = col_double(),
  PValue = col_double(),
  FDR = col_double(),
  Nhood = col_double(),
  SpatialFDR = col_double(),
  annotation_indepth = col_character(),
  annotation_indepth_fraction = col_double(),
  annotation_lineage = col_character()
)
# 
# liver_milo_2 <- Milo(as(liver_milo, 'SingleCellExperiment'))
# 
# liver_milo_2@graph <- liver_milo@graph
# liver_milo@nhoodDistances <- liver_milo2@nhoodDistances
# liver_milo_2@graph <- liver_milo@graph

Visualize results

milo_res %>%
  ggplot(aes(logFC, -log10(SpatialFDR))) + 
  geom_point(size=0.4) +
  geom_hline(yintercept = -log10(0.1))

Check cell type composition of DA neighbourhoods

#' Add annotation of most frequent cell type per nhood to milo results table
add_nhood_coldata_to_res <- function(liver_milo, milo_res, coldata_col){
  nhood_counts <- sapply(seq_along(nhoods(liver_milo)), function(x) table(colData(liver_milo)[as.vector(nhoods(liver_milo)[[x]]), coldata_col]))
  nhood_counts <- t(nhood_counts)
  rownames(nhood_counts) <- seq_along(nhoods(liver_milo))
  max_val <- apply(nhood_counts, 1, function(x) colnames(nhood_counts)[which.max(x)])
  max_frac <- apply(nhood_counts, 1, function(x) max(x)/sum(x))
  milo_res[coldata_col] <- max_val
  milo_res[paste0(coldata_col, "_fraction")] <- max_frac
  return(milo_res)
}

milo_res <- add_nhood_coldata_to_res(liver_milo, milo_res, "annotation_indepth")
milo_res$annotation_lineage.x <- NULL
milo_res$annotation_lineage.y <- NULL
milo_res$annotation_lineage <- NULL
anno_df <- data.frame(liver_milo@colData) %>%
  distinct(annotation_lineage, annotation_indepth)
milo_res <- left_join(milo_res, anno_df, by="annotation_indepth")
rownames(milo_res) <- 1:nrow(milo_res)
Setting row names on a tibble is deprecated.

This shows that I can recover all the clusters where DA was detected in the original paper (see all the barplots for each lineage) and more! All in a single analysis, and without knowing where the subclusters are. Let’s bear in mind that positive logFC –> more cirrhotic, negative logFC —> more healthy

paper_DA <- list(cirrhotic=c("MPs (4)","MPs (5)",
                             "Endothelia (6)", "Endothelia (7)",
                             "Mes (3)",
                             "Tcells (2)",
                             "Myofibroblasts"
                             ),
                 healthy=c("MPs (7)",
                           "Endothelia (1)",
                           "Tcells (1)", "Tcells (3)","Tcells (1)",
                           "ILCs (1)"
                           )
                 )

expDA_df <- bind_rows(
  data.frame(annotation_indepth = paper_DA[["cirrhotic"]], pred_DA="cirrhotic"),
  data.frame(annotation_indepth = paper_DA[["healthy"]], pred_DA="healthy")
  )

pl1 <- milo_res %>%
  left_join(expDA_df) %>%
  mutate(is_signif = ifelse(SpatialFDR < 0.1, 1, 0)) %>%
  mutate(logFC_color = ifelse(is_signif==1, logFC, NA)) %>%
  arrange(annotation_lineage) %>%
  mutate(Nhood=factor(Nhood, levels=unique(Nhood))) %>%
  ggplot(aes(annotation_indepth, logFC, color=logFC_color)) +
  scale_color_gradient2() +
  guides(color="none") +
  xlab("annotation") + ylab("Log Fold Change") +
  ggbeeswarm::geom_quasirandom(alpha=1) +
  coord_flip() +
  facet_grid(annotation_lineage~., scales="free", space="free") +
  theme_bw(base_size=16) +
  theme(strip.text.y =  element_text(angle=0),
        axis.title.y = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(),
        )
Joining, by = "annotation_indepth"
pl2 <- milo_res %>%
  left_join(expDA_df) %>%
  # dplyr::filter(!is.na(pred_DA)) %>%
  group_by(annotation_indepth) %>%
  summarise(pred_DA=dplyr::first(pred_DA), annotation_lineage=dplyr::first(annotation_lineage)) %>%
  mutate(end=ifelse(pred_DA=="healthy", 0, 1),
         start=ifelse(pred_DA=="healthy", 1, 0)) %>%
  ggplot(aes(annotation_indepth, start, xend = annotation_indepth, yend = end, color=pred_DA)) +
  geom_segment(size=1,arrow=arrow(length = unit(0.1, "npc"), type="closed")) +
  coord_flip() +
  xlab("annotation") +
  facet_grid(annotation_lineage~.,
    # annotation_lineage~"Ramachandran et al.\nDA predictions", 
             scales="free", space="free") +
  # guides(color="none") +
  scale_color_brewer(palette="Set1", direction = -1, 
                     labels=c("enriched in cirrhotic", "enriched in healthy"),
                     na.translate = F,
                     name="Ramachandran et al.\nDA predictions") +
  guides(color=guide_legend(ncol = 1)) +
  theme_bw(base_size=16) +
  ylim(-0.1,1.1) +
  theme(strip.text.y = element_blank(),strip.text.x = element_text(angle=90),
        plot.margin = unit(c(0,0,0,0), "cm"), panel.grid = element_blank(),
        axis.title.x = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank(),
        legend.position = "bottom")
Joining, by = "annotation_indepth"
`summarise()` ungrouping output (override with `.groups` argument)
(pl2 + pl1 + 
  plot_layout(widths=c(1,10), guides = "collect") & theme(legend.position = 'top', legend.justification = 0)) +
  ggsave("~/milo_output/liver_DAcomparison.pdf", width=8, height = 13)

Visualization with nhood graph

liver_milo <- buildNhoodGraph(liver_milo)
[1] "Calculating nhood adjacency...."

Close-up on Endothelial lineage

Differential expression between DA neighbourhoods

I will try this on the endothelial lineage. I want to merge overlapping nhoods with significant DA and the same direction of logFC, and then test for differential expression between cells in up and down nhoods (I guess you could also do up or down VS all the rest). This allows us to perform a comparison without further clustering.

subset.nhoods[1:(length(subset.nhoods)-1)]
  [1]   11   20   21   22   26   46   49   50   83  104  112  118  119  128  132  149  151  156  162  193  226  233  246  272  295  296  309  315  325  330
 [31]  360  364  365  371  377  382  385  386  388  391  395  401  420  422  438  443  449  479  480  481  485  499  500  505  527  531  536  537  538  551
 [61]  553  559  560  569  576  594  605  613  614  620  621  645  660  666  682  690  702  705  711  716  725  726  736  738  751  752  768  772  773  781
 [91]  782  799  806  810  812  821  837  849  852  865  870  923  926  928  970  986 1002 1006 1010 1013 1051 1053 1054 1061 1073 1086 1088 1093 1096 1097
[121] 1108 1118 1121 1126 1137 1147 1148 1152 1153 1171 1182 1188 1190 1196 1214 1217 1224 1232 1236 1238 1241 1251 1256 1258 1262 1263 1266 1268 1269 1275
[151] 1277 1285 1289 1306 1312 1313 1339 1343 1348 1352 1367 1379 1380 1391 1419 1422 1424 1427 1433 1436 1443 1450 1454 1465 1481 1497 1502 1524 1528 1538
[181] 1540 1550 1568 1572 1582 1597 1608 1609 1619 1623 1627 1629 1640 1652 1653 1654 1659 1661 1663 1669 1673 1675 1677 1679 1680 1685 1690 1700 1702 1709
[211] 1714 1718 1726 1730 1732 1737 1739 1749 1765 1766 1771 1773 1787 1804 1805 1817 1828 1860 1864 1869 1872 1878 1887 1905 1910 1922 1926 1927 1930 1936
[241] 1946 1959 1972 1984 1989 2004 2020 2026 2041 2045 2053 2072 2079 2116 2118 2119 2122 2126 2130 2136 2140 2141 2145 2152 2155 2157 2164 2168 2177 2185
[271] 2190 2193 2199 2207 2209 2211 2215 2219 2227 2229 2233 2258 2260 2278 2291 2292 2334 2351 2355 2373 2377 2394 2396 2405 2423 2424 2429 2449 2450 2455
[301] 2462 2463 2473 2489 2491 2495 2498 2501 2504 2507 2508 2517 2527 2534 2552 2557 2559 2563 2567 2584 2585 2587 2589 2593 2602 2606 2609 2615 2620 2622
[331] 2626 2632 2639 2646 2653 2657 2664 2666 2672 2673 2675 2677 2684 2685 2691 2692 2695
endo_milo <- buildNhoodGraph(endo_milo)
[1] "Calculating nhood adjacency...."
'CD59' %in% endo_hvgs
[1] FALSE
nhood_markers <- findNhoodMarkers(liver_milo, milo_res, overlap=1, assay="logcounts", return.groups = TRUE,
                                  subset.row = endo_hvgs,
                                  subset.nhoods = milo_res$annotation_lineage=="Endothelia")
Found 1404 DA neighbourhoods at FDR 10%
Nhoods aggregated into 2 groups
marker_genes <-
  nhood_markers$dge %>%
  pivot_longer(cols=str_subset(colnames(nhood_markers$dge), "adj.P.Val_")) %>%
  pivot_longer(cols=str_subset(colnames(nhood_markers$dge), "logFC_"), names_to='smp', values_to="logFC") %>%
   mutate(name=str_remove(name, "adj.P.Val_"), smp=str_remove(smp,"logFC_")) %>%
  dplyr::filter(smp==name) %>%
  dplyr::filter(smp==1) %>%
  mutate(logFC_dir=ifelse(logFC < 0, "down", 'up')) %>%
  group_by(logFC_dir) %>%
  top_n(n=50, -log10(value)) %>%
  ungroup() %>%
  # dplyr::filter(value < 0.01 & abs(logFC) > 0.02) %>%
  pull(GeneID) %>%
  unique()


nhood_markers$dge %>%
  pivot_longer(cols=str_subset(colnames(nhood_markers$dge), "adj.P.Val_")) %>%
  pivot_longer(cols=str_subset(colnames(nhood_markers$dge), "logFC_"), names_to='smp', values_to="logFC") %>%
  mutate(name=str_remove(name, "adj.P.Val_"), smp=str_remove(smp,"logFC_")) %>%
  dplyr::filter(smp==name) %>%
  mutate(color=ifelse(value<0.05, 1, 0),
         label=ifelse(GeneID %in% marker_genes, GeneID,NA)) %>%
  ggplot(aes(logFC, -log10(value), color=color)) +
  geom_point(size=0.1) +
  facet_wrap(name~., scales="free") +
  geom_hline(yintercept = -log10(0.01)) +
  ggrepel::geom_text_repel(aes(label=label))

marker_genes <- nhood_markers$dge %>%
  dplyr::filter(adj.P.Val_1 < 0.01) %>%
  pull(GeneID)

Customize plotting for paper figure

x <- liver_milo
da.res <- milo_res

cluster_features = TRUE
alpha = 0.05
scale_to_1 = TRUE
subset.nhoods = milo_res$annotation_lineage=="Endothelia"
features <- marker_genes

expr_mat <- nhoodExpression(x)[features,]
colnames(expr_mat) <- 1:length(nhoods(x))

## Get nhood expression matrix
if (!is.null(subset.nhoods)) {
  expr_mat <- expr_mat[,subset.nhoods, drop=FALSE]
}

if (!isFALSE(scale_to_1)) {
  expr_mat <- t(apply(expr_mat, 1, function(x) (x - min(x))/(max(x)- min(x))))
}

rownames(expr_mat) <- sub(pattern = "-", replacement = ".", rownames(expr_mat)) ## To avoid problems when converting to data.frame

pl_df <- data.frame(t(expr_mat)) %>%
  rownames_to_column("Nhood") %>%
  mutate(Nhood=as.double(Nhood)) %>%
  left_join(da.res, by="Nhood") %>%
  mutate(logFC_rank=percent_rank(logFC)) 

## Top plot: nhoods ranked by DA log FC
pl_top <- pl_df %>%
  mutate(is_signif = ifelse(SpatialFDR < alpha, paste0("SpatialFDR < ", alpha), NA)) %>%
  ggplot(aes(logFC_rank, logFC)) +
  geom_hline(yintercept = 0, linetype=2) +
  geom_point(size=0.2, color="grey") +
  geom_point(data=.%>% filter(!is.na(is_signif)), aes(color=is_signif), size=1) +
  theme_bw(base_size=16) +
  ylab("DA logFC") +
  scale_color_manual(values="red", name="") +
  scale_x_continuous(expand = c(0.01, 0)) +
  theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), axis.title.x = element_blank())

## Bottom plot: gene expression heatmap
if (isTRUE(cluster_features)) {
  row.order <- hclust(dist(expr_mat))$order # clustering
  ordered_features <- rownames(expr_mat)[row.order]
} else {
  ordered_features <- rownames(expr_mat)
}

Quick GO term analysis

Let’s check the genes identified as markers for the disease subtypes. Are they significantly differentially expressed between DA neighbourhoods? Yes they are!

disease_endo_markers <- c("ACKR1", 'CD34',"VWA1")

data.frame(markers$negLogFC_2) %>%
  filter(FDR < 0.05) %>%
  .[disease_endo_markers,]

data.frame(markers$negLogFC_1) %>%
  filter(FDR < 0.05) %>%
  .[disease_endo_markers,]

Visualize some of the markers that differentiate DA neighbourhoods, by plotting the percent of cells expressing each gene in a nhood.

## Define plotting functions
.calculate_nhood_perc_expression <- function(milo, nhoods, gene){
  gene_cnts <- counts(milo)[gene,]
  perc_expr <- sapply(nhoods(milo)[nhoods], function(x) sum(gene_cnts[x]>0)/length(x))
  perc_expr <- setNames(perc_expr, nhoods)
  return(perc_expr)
  }

.plot_nhood_expression <- function(milo, nhoods, features){
  perc_expr_mat <- sapply(features, 
                          function(x) .calculate_nhood_perc_expression(milo, nhoods, x))
  
  pl_df <- data.frame(perc_expr_mat) %>%
    rownames_to_column("Nhood") %>%
    mutate(Nhood=as.double(Nhood)) %>%
    left_join(milo_res) %>%
    mutate(logFC_rank=rank(logFC)) 
  
  pl_top <- pl_df %>%
      mutate(is_signif = ifelse(SpatialFDR < 0.1, "SpatialFDR < 0.1", NA)) %>%
      ggplot(aes(logFC_rank, logFC)) +
      geom_hline(yintercept = 0, linetype=2) +
      geom_point(size=0.2) +
      geom_point(data=.%>% filter(!is.na(is_signif)), aes(color=is_signif), size=0.5) +
      theme_bw() +
      scale_color_manual(values="red", name="") +
      theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), axis.title.x = element_blank())
    
  pl_bottom <- pl_df %>%
    pivot_longer(cols=features, names_to='feature', values_to="perc_expressed") %>%
    mutate(feature=factor(feature, levels=features)) %>%
    ggplot(aes(logFC_rank, feature, fill=perc_expressed)) + 
    geom_tile() +
    scale_fill_viridis_c(option="magma") +
    ggbio::theme_clear()
  
  (pl_top / pl_bottom) + plot_layout(heights = c(1,2))
}
endo_nhoods <- endo_res %>%  pull(Nhood)

## Select genes and sort by AUC
feats_neg2 <-
  data.frame(markers$negLogFC_2) %>% 
  top_n(50, - log10(FDR)) %>%
  arrange(AUC.posLogFC_1) %>%
  rownames()

.plot_nhood_expression(liver_milo, endo_nhoods, features=feats)

As described in the paper, we have that genes associated with extracellular matrix organization (e.g. VIM, ) are over expressed

## Select genes and sort by AUC
feats_neg1 <-
  data.frame(markers$negLogFC_1) %>% 
  top_n(50, - log10(FDR)) %>%
  arrange(AUC.posLogFC_1) %>%
  rownames()

.plot_nhood_expression(liver_milo, endo_nhoods, features=feats)
feats_neg1vsNeg2 <-
  data.frame(markers$negLogFC_1) %>% 
  top_n(50, - log10(FDR)) %>%
  arrange(AUC.negLogFC_2) %>%
  rownames()

.plot_nhood_expression(liver_milo, endo_nhoods, features=feats_neg1vsNeg2)
Ci0tLQp0aXRsZTogIk1pbG8gb24gZGlzZWFzZSBWUyBoZWFsdGh5IGRhdGFzZXQiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkoaXJsYmEpCiAgbGlicmFyeShEcm9wbGV0VXRpbHMpCiAgbGlicmFyeShzY2F0ZXIpCiAgbGlicmFyeShzY3JhbikKICBsaWJyYXJ5KFNldXJhdCkgIyMganVzdCA0IGxvYWRpbmcgdGhlIG9iamVjdAogIGxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpCiAgbGlicmFyeShtaWxvUikKICBsaWJyYXJ5KHBhdGNod29yaykKICBsaWJyYXJ5KGlncmFwaCkKICB9KQpgYGAKClVzaW5nIGRhdGEgZnJvbSBbUmFtYWNoYW5kcmFuIGV0IGFsLiAyMDE5XShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL3M0MTU4Ni0wMTktMTYzMS0zI1NlYzEpIChHRU8gYWNjZXNzaWlvbjogR1NFMTM2MTAzKS4gVGhlIFNldXJhdCBvYmplY3Qgd2FzIGRvd25sb2FkZWQgZnJvbSBodHRwczovL2RhdGFzaGFyZS5pcy5lZC5hYy51ay9oYW5kbGUvMTAyODMvMzQzMywgdXBvbiByZXF1ZXN0IHRvIHRoZSBhdXRob3JzLgoKYGBge3J9CmxvYWQoIi9uZnMvdGVhbTIwNS9lZDYvZGF0YS9SYW1hY2hhbmRyYW4yMDE5X2xpdmVyL3Rpc3N1ZS5yZGF0YSIpCmBgYAoKYGBge3J9CiMjIENvbnZlcnQgdG8gU2luZ2xlQ2VsbEV4cGVyaW1lbnQKbGl2ZXJfc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGFzc2F5ID0gbGlzdChjb3VudHM9dGlzc3VlQHJhdy5kYXRhLCBsb2djb3VudHM9dGlzc3VlQGRhdGEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSB0aXNzdWVAbWV0YS5kYXRhKQpgYGAKCiMjIyBGZWF0dXJlIHNlbGVjdGlvbgoKYGBge3J9CmRlY19saXZlciA8LSBtb2RlbEdlbmVWYXIobGl2ZXJfc2NlKQoKIyBWaXN1YWxpemluZyB0aGUgZml0OgpmaXRfbGl2ZXIgPC0gbWV0YWRhdGEoZGVjX2xpdmVyKQpwbG90KGZpdF9saXZlciRtZWFuLCBmaXRfbGl2ZXIkdmFyLCB4bGFiPSJNZWFuIG9mIGxvZy1leHByZXNzaW9uIiwKICAgIHlsYWI9IlZhcmlhbmNlIG9mIGxvZy1leHByZXNzaW9uIikKCmh2Z3MgPC0gZ2V0VG9wSFZHcyhkZWNfbGl2ZXIsIG49MzAwMCkKYGBgCgojIyMgRGltIHJlZHVjdGlvbgoKYGBge3IsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xNH0KbGl2ZXJfc2NlIDwtIHJ1blBDQShsaXZlcl9zY2UsIHN1YnNldF9yb3c9aHZncywgbmNvbXBvbmVudHM9MTEpCgpwbG90UENBKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJjb25kaXRpb24iLCBuY29tcG9uZW50cz0zKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQpsaXZlcl9zY2UgPC0gcnVuVU1BUChsaXZlcl9zY2UsIGRpbXJlZD0iUENBIiwgbmNvbXBvbmVudHM9MikKCnNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9ImNvbmRpdGlvbiIsIHBvaW50X2FscGhhPTEsICBwb2ludF9zaXplPTAuNSkgCnNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9ImRhdGFzZXQiLCBwb2ludF9hbHBoYT0wLjMsICBwb2ludF9zaXplPTAuNSkKc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iYW5ub3RhdGlvbl9saW5lYWdlIiwgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUsIHRleHRfYnk9J2Fubm90YXRpb25fbGluZWFnZScpCiMgc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0nYW5ub3RhdGlvbl9pbmRlcHRoJywgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUsIHRleHRfYnk9J2Fubm90YXRpb25faW5kZXB0aCcpCmBgYAoKIyMjIEFwcGx5IE1pbG8KCkxldCdzIHRlc3QgZm9yIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgYmV0d2VlbiBoZWFsdGh5IGFuZCBjaXJyaG90aWMgbGl2ZXJzLgoKIyMjIyBTYW1wbGUgbmVpZ2hib3VyaG9vZHMKCmBgYHtyfQpsaXZlcl9taWxvIDwtIE1pbG8obGl2ZXJfc2NlKQoKIyMgQnVpbGQgS05OIGdyYXBoCmxpdmVyX21pbG8gPC0gYnVpbGRHcmFwaChsaXZlcl9taWxvLCBkID0gMTEsIGs9MzApCgojIyBDb21wdXRlIG5laWdoYm91cmhvb2RzIHdpdGggcmVmaW5lZCBzYW1wbGluZwpsaXZlcl9taWxvIDwtIG1ha2VOaG9vZHMobGl2ZXJfbWlsbywgaz0zMCwgZD0xMSwgcHJvcCA9IDAuMDUsIHJlZmluZWQ9VFJVRSkKcGxvdE5ob29kU2l6ZUhpc3QobGl2ZXJfbWlsbywgYmlucz0xNTApCmBgYAoKIyMjIyBNYWtlIGRlc2lnbiBtYXRyaXgKCmBgYHtyfQpsaXZlcl9tZXRhIDwtIGFzLnRpYmJsZShjb2xEYXRhKGxpdmVyX21pbG8pWyxjKCJkYXRhc2V0IiwiY29uZGl0aW9uIildKSAKbGl2ZXJfbWV0YSA8LSBkaXN0aW5jdChsaXZlcl9tZXRhKSAlPiUKICBtdXRhdGUoY29uZGl0aW9uPWZhY3Rvcihjb25kaXRpb24sIGxldmVscz1jKCJVbmluanVyZWQiLCAiQ2lycmhvdGljIikpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImRhdGFzZXQiKQpgYGAKCiMjIyMgVGVzdCBEQQoKCmBgYHtyfQpsaXZlcl9taWxvIDwtIGNvdW50Q2VsbHMobGl2ZXJfbWlsbywgc2FtcGxlcyA9ICJkYXRhc2V0IiwgbWV0YS5kYXRhID0gZGF0YS5mcmFtZShjb2xEYXRhKGxpdmVyX21pbG8pWyxjKCJkYXRhc2V0IiwiY29uZGl0aW9uIildKSApCgptaWxvX3JlcyA8LSB0ZXN0Tmhvb2RzKGxpdmVyX21pbG8sIGRlc2lnbiA9IH4gY29uZGl0aW9uLCBkZXNpZ24uZGYgPSBsaXZlcl9tZXRhLCBmZHIud2VpZ2h0aW5nID0gImstZGlzdGFuY2UiKQpgYGAKCmBgYHtyfQojIyBTYXZlIG1pbG8gb2JqZWN0IGFuZCByZXN1bHRzCnNhdmVSRFMobGl2ZXJfbWlsbywiL25mcy90ZWFtMjA1L2VkNi9kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvdGlzc3VlX21pbG8uUkRTIikKd3JpdGVfY3N2KG1pbG9fcmVzLCAiL25mcy90ZWFtMjA1L2VkNi9kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvbWlsb19yZXN1bHRzLmNzdiIpCmBgYApgYGB7cn0KbGl2ZXJfbWlsbyA8LSByZWFkUkRTKCIvbmZzL3RlYW0yMDUvZWQ2L2RhdGEvUmFtYWNoYW5kcmFuMjAxOV9saXZlci90aXNzdWVfbWlsby5SRFMiKQptaWxvX3JlcyA8LSByZWFkX2NzdigiL25mcy90ZWFtMjA1L2VkNi9kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvbWlsb19yZXN1bHRzLmNzdiIpCiMgCiMgbGl2ZXJfbWlsb18yIDwtIE1pbG8oYXMobGl2ZXJfbWlsbywgJ1NpbmdsZUNlbGxFeHBlcmltZW50JykpCiMgCiMgbGl2ZXJfbWlsb18yQGdyYXBoIDwtIGxpdmVyX21pbG9AZ3JhcGgKIyBsaXZlcl9taWxvQG5ob29kRGlzdGFuY2VzIDwtIGxpdmVyX21pbG8yQG5ob29kRGlzdGFuY2VzCiMgbGl2ZXJfbWlsb18yQGdyYXBoIDwtIGxpdmVyX21pbG9AZ3JhcGgKYGBgCgoKClZpc3VhbGl6ZSByZXN1bHRzCmBgYHtyfQptaWxvX3JlcyAlPiUKICBnZ3Bsb3QoYWVzKGxvZ0ZDLCAtbG9nMTAoU3BhdGlhbEZEUikpKSArIAogIGdlb21fcG9pbnQoc2l6ZT0wLjQpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoMC4xKSkKYGBgCgpDaGVjayBjZWxsIHR5cGUgY29tcG9zaXRpb24gb2YgREEgbmVpZ2hib3VyaG9vZHMKCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD0xMH0KIycgQWRkIGFubm90YXRpb24gb2YgbW9zdCBmcmVxdWVudCBjZWxsIHR5cGUgcGVyIG5ob29kIHRvIG1pbG8gcmVzdWx0cyB0YWJsZQphZGRfbmhvb2RfY29sZGF0YV90b19yZXMgPC0gZnVuY3Rpb24obGl2ZXJfbWlsbywgbWlsb19yZXMsIGNvbGRhdGFfY29sKXsKICBuaG9vZF9jb3VudHMgPC0gc2FwcGx5KHNlcV9hbG9uZyhuaG9vZHMobGl2ZXJfbWlsbykpLCBmdW5jdGlvbih4KSB0YWJsZShjb2xEYXRhKGxpdmVyX21pbG8pW2FzLnZlY3RvcihuaG9vZHMobGl2ZXJfbWlsbylbW3hdXSksIGNvbGRhdGFfY29sXSkpCiAgbmhvb2RfY291bnRzIDwtIHQobmhvb2RfY291bnRzKQogIHJvd25hbWVzKG5ob29kX2NvdW50cykgPC0gc2VxX2Fsb25nKG5ob29kcyhsaXZlcl9taWxvKSkKICBtYXhfdmFsIDwtIGFwcGx5KG5ob29kX2NvdW50cywgMSwgZnVuY3Rpb24oeCkgY29sbmFtZXMobmhvb2RfY291bnRzKVt3aGljaC5tYXgoeCldKQogIG1heF9mcmFjIDwtIGFwcGx5KG5ob29kX2NvdW50cywgMSwgZnVuY3Rpb24oeCkgbWF4KHgpL3N1bSh4KSkKICBtaWxvX3Jlc1tjb2xkYXRhX2NvbF0gPC0gbWF4X3ZhbAogIG1pbG9fcmVzW3Bhc3RlMChjb2xkYXRhX2NvbCwgIl9mcmFjdGlvbiIpXSA8LSBtYXhfZnJhYwogIHJldHVybihtaWxvX3JlcykKfQoKbWlsb19yZXMgPC0gYWRkX25ob29kX2NvbGRhdGFfdG9fcmVzKGxpdmVyX21pbG8sIG1pbG9fcmVzLCAiYW5ub3RhdGlvbl9pbmRlcHRoIikKbWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlLnggPC0gTlVMTAptaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2UueSA8LSBOVUxMCm1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZSA8LSBOVUxMCmFubm9fZGYgPC0gZGF0YS5mcmFtZShsaXZlcl9taWxvQGNvbERhdGEpICU+JQogIGRpc3RpbmN0KGFubm90YXRpb25fbGluZWFnZSwgYW5ub3RhdGlvbl9pbmRlcHRoKQptaWxvX3JlcyA8LSBsZWZ0X2pvaW4obWlsb19yZXMsIGFubm9fZGYsIGJ5PSJhbm5vdGF0aW9uX2luZGVwdGgiKQoKYGBgCgpUaGlzIHNob3dzIHRoYXQgSSBjYW4gcmVjb3ZlciBhbGwgdGhlIGNsdXN0ZXJzIHdoZXJlIERBIHdhcyBkZXRlY3RlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXIgKHNlZSBhbGwgdGhlIGJhcnBsb3RzIGZvciBlYWNoIGxpbmVhZ2UpIGFuZCBtb3JlISBBbGwgaW4gYSBzaW5nbGUgYW5hbHlzaXMsIGFuZCB3aXRob3V0IGtub3dpbmcgd2hlcmUgdGhlIHN1YmNsdXN0ZXJzIGFyZS4gTGV0J3MgYmVhciBpbiBtaW5kIHRoYXQgcG9zaXRpdmUgbG9nRkMgLS0+IG1vcmUgY2lycmhvdGljLCBuZWdhdGl2ZSBsb2dGQyAtLS0+IG1vcmUgaGVhbHRoeQoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KcGFwZXJfREEgPC0gbGlzdChjaXJyaG90aWM9YygiTVBzICg0KSIsIk1QcyAoNSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhICg2KSIsICJFbmRvdGhlbGlhICg3KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lcyAoMykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUY2VsbHMgKDIpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXlvZmlicm9ibGFzdHMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICBoZWFsdGh5PWMoIk1QcyAoNykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYSAoMSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiVGNlbGxzICgxKSIsICJUY2VsbHMgKDMpIiwiVGNlbGxzICgxKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJJTENzICgxKSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICkKCmV4cERBX2RmIDwtIGJpbmRfcm93cygKICBkYXRhLmZyYW1lKGFubm90YXRpb25faW5kZXB0aCA9IHBhcGVyX0RBW1siY2lycmhvdGljIl1dLCBwcmVkX0RBPSJjaXJyaG90aWMiKSwKICBkYXRhLmZyYW1lKGFubm90YXRpb25faW5kZXB0aCA9IHBhcGVyX0RBW1siaGVhbHRoeSJdXSwgcHJlZF9EQT0iaGVhbHRoeSIpCiAgKQoKcGwxIDwtIG1pbG9fcmVzICU+JQogIGxlZnRfam9pbihleHBEQV9kZikgJT4lCiAgbXV0YXRlKGlzX3NpZ25pZiA9IGlmZWxzZShTcGF0aWFsRkRSIDwgMC4xLCAxLCAwKSkgJT4lCiAgbXV0YXRlKGxvZ0ZDX2NvbG9yID0gaWZlbHNlKGlzX3NpZ25pZj09MSwgbG9nRkMsIE5BKSkgJT4lCiAgYXJyYW5nZShhbm5vdGF0aW9uX2xpbmVhZ2UpICU+JQogIG11dGF0ZShOaG9vZD1mYWN0b3IoTmhvb2QsIGxldmVscz11bmlxdWUoTmhvb2QpKSkgJT4lCiAgZ2dwbG90KGFlcyhhbm5vdGF0aW9uX2luZGVwdGgsIGxvZ0ZDLCBjb2xvcj1sb2dGQ19jb2xvcikpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIoKSArCiAgZ3VpZGVzKGNvbG9yPSJub25lIikgKwogIHhsYWIoImFubm90YXRpb24iKSArIHlsYWIoIkxvZyBGb2xkIENoYW5nZSIpICsKICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKGFscGhhPTEpICsKICBjb29yZF9mbGlwKCkgKwogIGZhY2V0X2dyaWQoYW5ub3RhdGlvbl9saW5lYWdlfi4sIHNjYWxlcz0iZnJlZSIsIHNwYWNlPSJmcmVlIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xNikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9ICBlbGVtZW50X3RleHQoYW5nbGU9MCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICkKCnBsMiA8LSBtaWxvX3JlcyAlPiUKICBsZWZ0X2pvaW4oZXhwREFfZGYpICU+JQogICMgZHBseXI6OmZpbHRlcighaXMubmEocHJlZF9EQSkpICU+JQogIGdyb3VwX2J5KGFubm90YXRpb25faW5kZXB0aCkgJT4lCiAgc3VtbWFyaXNlKHByZWRfREE9ZHBseXI6OmZpcnN0KHByZWRfREEpLCBhbm5vdGF0aW9uX2xpbmVhZ2U9ZHBseXI6OmZpcnN0KGFubm90YXRpb25fbGluZWFnZSkpICU+JQogIG11dGF0ZShlbmQ9aWZlbHNlKHByZWRfREE9PSJoZWFsdGh5IiwgMCwgMSksCiAgICAgICAgIHN0YXJ0PWlmZWxzZShwcmVkX0RBPT0iaGVhbHRoeSIsIDEsIDApKSAlPiUKICBnZ3Bsb3QoYWVzKGFubm90YXRpb25faW5kZXB0aCwgc3RhcnQsIHhlbmQgPSBhbm5vdGF0aW9uX2luZGVwdGgsIHllbmQgPSBlbmQsIGNvbG9yPXByZWRfREEpKSArCiAgZ2VvbV9zZWdtZW50KHNpemU9MSxhcnJvdz1hcnJvdyhsZW5ndGggPSB1bml0KDAuMSwgIm5wYyIpLCB0eXBlPSJjbG9zZWQiKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiYW5ub3RhdGlvbiIpICsKICBmYWNldF9ncmlkKGFubm90YXRpb25fbGluZWFnZX4uLAogICAgIyBhbm5vdGF0aW9uX2xpbmVhZ2V+IlJhbWFjaGFuZHJhbiBldCBhbC5cbkRBIHByZWRpY3Rpb25zIiwgCiAgICAgICAgICAgICBzY2FsZXM9ImZyZWUiLCBzcGFjZT0iZnJlZSIpICsKICAjIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIsIGRpcmVjdGlvbiA9IC0xLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoImVucmljaGVkIGluIGNpcnJob3RpYyIsICJlbnJpY2hlZCBpbiBoZWFsdGh5IiksCiAgICAgICAgICAgICAgICAgICAgIG5hLnRyYW5zbGF0ZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlJhbWFjaGFuZHJhbiBldCBhbC5cbkRBIHByZWRpY3Rpb25zIikgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobmNvbCA9IDEpKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE2KSArCiAgeWxpbSgtMC4xLDEuMSkgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSxzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTApLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwwLDApLCAiY20iKSwgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoocGwyICsgcGwxICsgCiAgcGxvdF9sYXlvdXQod2lkdGhzPWMoMSwxMCksIGd1aWRlcyA9ICJjb2xsZWN0IikgJiB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJywgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAwKSkgKwogIGdnc2F2ZSgifi9taWxvX291dHB1dC9saXZlcl9EQWNvbXBhcmlzb24ucGRmIiwgd2lkdGg9OCwgaGVpZ2h0ID0gMTMpCmBgYAoKIyMjIFZpc3VhbGl6YXRpb24gd2l0aCBuaG9vZCBncmFwaAoKYGBge3J9CmxpdmVyX21pbG8gPC0gYnVpbGROaG9vZEdyYXBoKGxpdmVyX21pbG8pCmBgYApgYGB7ciwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTEwfQpjb2xvdXJDb3VudCA9IGxlbmd0aCh1bmlxdWUobGl2ZXJfbWlsbyRhbm5vdGF0aW9uX2xpbmVhZ2UpKQpnZXRQYWxldHRlID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJTcGVjdHJhbCIpKQoKdW1hcF9kZiA8LSBkYXRhLmZyYW1lKHJlZHVjZWREaW0obGl2ZXJfbWlsbywgIlVNQVAiKSkKY29sbmFtZXModW1hcF9kZikgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCgp1bWFwMSA8LSBjYmluZCh1bWFwX2RmLCBhbm5vdGF0aW9uX2xpbmVhZ2U9bGl2ZXJfbWlsbyRhbm5vdGF0aW9uX2xpbmVhZ2UpICU+JQogIGdncGxvdChhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG9yPWFzLmNoYXJhY3Rlcihhbm5vdGF0aW9uX2xpbmVhZ2UpKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0wLjUpICsKICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IC4gJT4lIAogICAgICAgICAgICAgIGdyb3VwX2J5KGFubm90YXRpb25fbGluZWFnZSkgJT4lIAogICAgICAgICAgICAgIHN1bW1hcmlzZShVTUFQXzE9bWVhbihVTUFQXzEpLCBVTUFQXzI9bWVhbihVTUFQXzIpKSwKICAgICAgICAgICAgYWVzKGxhYmVsPWFubm90YXRpb25fbGluZWFnZSksIGNvbG9yPSJibGFjayIsIHNpemU9NAogICAgICAgICAgICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdldFBhbGV0dGUoY29sb3VyQ291bnQpKSArCiAgZ3VpZGVzKGNvbG9yPSJub25lIikgKwogIHhsYWIoIlVNQVAxIikgKyB5bGFiKCJVTUFQMiIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE2KSArCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKQoKdW1hcDIgPC0gY2JpbmQodW1hcF9kZiwgY29uZGl0aW9uPWFzLmNoYXJhY3RlcihsaXZlcl9taWxvJGNvbmRpdGlvbikpICU+JQogIGdncGxvdChhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG9yPWNvbmRpdGlvbikpICsKICBnZW9tX3BvaW50KHNpemU9MC41KSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiLCBuYW1lPScnKSArCiAgeGxhYigiVU1BUDEiKSArIHlsYWIoIlVNQVAyIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTIpKSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTYpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj1jKDAuOSwwLjkpKQoKCm5oX2dyYXBoX3BsIDwtIHBsb3ROaG9vZEdyYXBoREEobGl2ZXJfbWlsbywgbWlsb19yZXMsIGFscGhhID0gMC4wNSkgKwogIGNvb3JkX2ZpeGVkKCkKCigodW1hcDEgLyB1bWFwMiArIHBsb3RfbGF5b3V0KCkpIHwgbmhfZ3JhcGhfcGwpICsgCiAgcGxvdF9sYXlvdXQod2lkdGhzID0gYygxLDIpKSArCiAgZ2dzYXZlKCJ+L21pbG9fb3V0cHV0L2xpdmVyX2VtYmVkZGluZy5wZGYiLCB3aWR0aD0xNSwgaGVpZ2h0ID0gMTApCmBgYAoKCiMjIENsb3NlLXVwIG9uIEVuZG90aGVsaWFsIGxpbmVhZ2UKCgo8IS0tIENvbXB1dGUgSFYgZ2VuZXMgZm9yIHN1YnNldCAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gZGVjX2VuZG8gPC0gbW9kZWxHZW5lVmFyKGVuZG9fbWlsbykgLS0+CjwhLS0gZW5kb19odmdzIDwtIGdldFRvcEhWR3MoZGVjX2VuZG8sIG49MzAwMCkgLS0+CjwhLS0gYGBgIC0tPgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04fQojIGVuZG9fbWlsbyA8LSBzY2F0ZXI6OnJ1blBDQShlbmRvX21pbG8sIHN1YnNldF9yb3c9ZW5kb19odmdzLCBuY29tcG9uZW50cz0xMSkKZW5kb19taWxvIDwtIHNjYXRlcjo6cnVuVU1BUChsaXZlcl9taWxvWyxsaXZlcl9taWxvJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiXSwgIGRpbXJlZD0nUENBJykKCnVtYXBfZGYgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKGVuZG9fbWlsbywgIlVNQVAiKSkKY29sbmFtZXModW1hcF9kZikgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCgplbmRvX3VtYXAgPC0gY2JpbmQodW1hcF9kZiwgY29uZGl0aW9uPWVuZG9fbWlsbyRjb25kaXRpb24pICU+JQogICBnZ3Bsb3QoYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvcj1jb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplPTAuNSkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIiwgbmFtZT0nJykgKwogIHhsYWIoIlVNQVAxIikgKyB5bGFiKCJVTUFQMiIpICsKICBjb29yZF9maXhlZCgpICsKICBndWlkZXMoY29sb3I9Im5vbmUiKSArCiAgZmFjZXRfd3JhcChjb25kaXRpb25+LiwgbmNvbD0xKSArCiAgdGhlbWVfbm90aGluZygpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj1jKDAuOSwwLjkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9TkEpLCBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpKQoKYGBgCjwhLS0gYyAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gbmhvb2RHcmFwaChlbmRvX21pbG8pIDwtIHN1YmdyYXBoKG5ob29kR3JhcGgobGl2ZXJfbWlsbyksIHdoaWNoKG1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiKSkgLS0+CjwhLS0gc3Vic2V0X25oX2l4cyA8LSBjb2xuYW1lcyhsaXZlcl9taWxvKVt1bmxpc3Qobmhvb2RJbmRleChsaXZlcl9taWxvKVt3aGljaChtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIildKV0gLS0+Cgo8IS0tIHdoaWNoKCFzdWJzZXRfbmhfaXhzICVpbiUgY29sbmFtZXMoZW5kb19taWxvKSkgLS0+CjwhLS0gZW5kb19taWxvWyxzdWJzZXRfbmhfaXhzXSAtLT4KCjwhLS0gbmV3X2l4cyA8LSAxOm5jb2woZW5kb19taWxvKSAtLT4KPCEtLSBzZXROYW1lcyhuZXdfaXhzLCBvbGRfaXhzKSAtLT4KCjwhLS0gdW5saXN0KG5ob29kSW5kZXgoZW5kb19taWxvKVt3aGljaChtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIildKSAtLT4KPCEtLSBuaG9vZEluZGV4KGVuZG9fbWlsbykgLS0+CjwhLS0gdmVydGV4X2F0dHIobmhvb2RHcmFwaChlbmRvX21pbG8pLCAibmFtZSIpIDwtICAtLT4KPCEtLSBgYGAgLS0+CgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTR9CmxpdmVyX21pbG8yIDwtIGxpdmVyX21pbG8Kc3Vic2V0Lm5ob29kcyA8LSB3aGljaChtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIikKCnJlZHVjZWREaW0obGl2ZXJfbWlsbzIsICJVTUFQIilbY29sbmFtZXMoZW5kb19taWxvKSxdIDwtIHJlZHVjZWREaW0oZW5kb19taWxvLCAiVU1BUCIpIAoKZW5kb19nciA8LSBwbG90Tmhvb2RHcmFwaERBKGxpdmVyX21pbG8yLCBtaWxvX3JlcywgCiAgICAgICAgICAgICAgICAgc3Vic2V0Lm5ob29kcyA9c3Vic2V0Lm5ob29kc1sxOihsZW5ndGgoc3Vic2V0Lm5ob29kcyktMSldLCBhbHBoYSA9IDEpCgoKKChlbmRvX3VtYXAgKyBlbmRvX2dyICkgKyAKICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsMiksIAogICAgICAgICAgICAgICAgZ3VpZGVzID0gImNvbGxlY3QiCiAgICAgICAgICAgICAgICApKSArCiAgZ2dzYXZlKCJ+L21pbG9fb3V0cHV0L2xpdmVyX2VuZG9HcmFwaC5wZGYiLCB3aWR0aD05LCBoZWlnaHQgPSA1KSAgCmBgYAoKCiMjIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiZXR3ZWVuIERBIG5laWdoYm91cmhvb2RzCgpJIHdpbGwgdHJ5IHRoaXMgb24gdGhlIGVuZG90aGVsaWFsIGxpbmVhZ2UuIEkgd2FudCB0byBtZXJnZSBvdmVybGFwcGluZyBuaG9vZHMgd2l0aCBzaWduaWZpY2FudCBEQSBhbmQgdGhlIHNhbWUgZGlyZWN0aW9uIG9mIGxvZ0ZDLCBhbmQgdGhlbiB0ZXN0IGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiZXR3ZWVuIGNlbGxzIGluIHVwIGFuZCBkb3duIG5ob29kcyAoSSBndWVzcyB5b3UgY291bGQgYWxzbyBkbyB1cCBvciBkb3duIFZTIGFsbCB0aGUgcmVzdCkuIFRoaXMgYWxsb3dzIHVzIHRvIHBlcmZvcm0gYSBjb21wYXJpc29uIHdpdGhvdXQgZnVydGhlciBjbHVzdGVyaW5nLgoKYGBge3J9CmVuZG9fbWlsbyA8LSBsaXZlcl9taWxvWyx3aGljaChsaXZlcl9taWxvJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiKV0KZW5kb19yZXMgPC0gZHBseXI6OmZpbHRlcihtaWxvX3JlcywgYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIpCgpyb3duYW1lcyhlbmRvX3JlcykgPC0gcm93bmFtZXMobWlsb19yZXMpW3doaWNoKG1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiKV0KYGBgCgpgYGB7cn0KZW5kb19taWxvIDwtIGJ1aWxkTmhvb2RHcmFwaChlbmRvX21pbG8pCgojIHBsb3ROaG9vZEdyYXBoKGxpdmVyX21pbG9bLHcobGl2ZXJfbWlsbyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIildLCBjb2xvdXJfYnkgPSAnYW5ub3RhdGlvbl9saW5lYWdlJykKCnBsb3ROaG9vZEdyYXBoREEoZW5kb19taWxvLCBlbmRvX21pbG9fcmVzKQpgYGAKCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBlbmRvX21pbG8gPC0gcnVuUENBKGVuZG9fbWlsbykgLS0+CjwhLS0gZW5kb19taWxvIDwtIGJ1aWxkR3JhcGgoZW5kb19taWxvKSAtLT4KCjwhLS0gZW5kb19taWxvIDwtIHJ1blVNQVAoZW5kb19taWxvKSAtLT4KPCEtLSBwbG90VU1BUChlbmRvX21pbG8sIGNvbG91cl9ieT0iYW5ub3RhdGlvbl9pbmRlcHRoIikgLS0+CjwhLS0gYGBgIC0tPgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBlbmRvX21pbG8gPC0gbWFrZU5ob29kcyhlbmRvX21pbG8pIC0tPgo8IS0tIGVuZG9fbWlsbyA8LSBjb3VudENlbGxzKGVuZG9fbWlsbywgc2FtcGxlcyA9ICJkYXRhc2V0IiwgbWV0YS5kYXRhID0gZGF0YS5mcmFtZShjb2xEYXRhKGVuZG9fbWlsbylbLGMoImRhdGFzZXQiLCJjb25kaXRpb24iKV0pICkgLS0+Cgo8IS0tIGVuZG9fbWlsb19yZXMgPC0gdGVzdE5ob29kcyhlbmRvX21pbG8sIGRlc2lnbiA9IH4gY29uZGl0aW9uLCBkZXNpZ24uZGYgPSBsaXZlcl9tZXRhLCBmZHIud2VpZ2h0aW5nID0gImstZGlzdGFuY2UiKSAtLT4KCjwhLS0gYGBgIC0tPgoKYGBge3J9CmRlY19saXZlciA8LSBtb2RlbEdlbmVWYXIobGl2ZXJfbWlsbykKCiMgVmlzdWFsaXppbmcgdGhlIGZpdDoKZml0X2xpdmVyIDwtIG1ldGFkYXRhKGRlY19saXZlcikKcGxvdChmaXRfbGl2ZXIkbWVhbiwgZml0X2xpdmVyJHZhciwgeGxhYj0iTWVhbiBvZiBsb2ctZXhwcmVzc2lvbiIsCiAgICB5bGFiPSJWYXJpYW5jZSBvZiBsb2ctZXhwcmVzc2lvbiIpCgpodmdzIDwtIGdldFRvcEhWR3MoZGVjX2xpdmVyLCBuPTMwMDApCgpwbG90KGZpdF9saXZlciRtZWFuLCBmaXRfbGl2ZXIkdmFyLCB4bGFiPSJNZWFuIG9mIGxvZy1leHByZXNzaW9uIiwKICAgICBjb2wgPSBpZmVsc2UobmFtZXMoZml0X2xpdmVyJG1lYW4pICVpbiUgaHZncywgJ3JlZCcsICJibGFjayIpLAogICAgeWxhYj0iVmFyaWFuY2Ugb2YgbG9nLWV4cHJlc3Npb24iKQoKIyMga2VlcCBIViBnZW5lcyBleHByZXNzZWQgaW4gYXQgbGVhc3QgNSUgb2YgZW5kb3RoZWxpYWwgY2VsbHMKZW5kb19odmdfY250cyA8LSBjb3VudHMobGl2ZXJfbWlsbylbaHZncyxsaXZlcl9taWxvJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiXQplbmRvX2h2Z3MgPC0gaHZnc1socm93U3VtcyhlbmRvX2h2Z19jbnRzIT0wKSA+IChuY29sKGVuZG9faHZnX2NudHMpLzEwMCkqNSkgJiAocm93U3VtcyhlbmRvX2h2Z19jbnRzIT0wKSA8IChuY29sKGVuZG9faHZnX2NudHMpLzEwMCkqODApXSAKYGBgCgoKCgpgYGB7cn0Kcm93bmFtZXMobWlsb19yZXMpIDwtIG5hbWVzKG5ob29kcyhsaXZlcl9taWxvKSkgIyMgSWYgSSBkb24ndCBzZXQgdGhlIG5ob29kIGluZGV4IGFzIG5hbWUgdGhlIGdyb3VwaW5nIGRvZXNuJ3QKbmhvb2RfbWFya2VycyA8LSBmaW5kTmhvb2RNYXJrZXJzKGxpdmVyX21pbG8sIG1pbG9fcmVzLCBvdmVybGFwPTEsIGFzc2F5PSJsb2djb3VudHMiLCByZXR1cm4uZ3JvdXBzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5yb3cgPSBlbmRvX2h2Z3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gbWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIpCgpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE3fQptYXJrZXJfZ2VuZXMgPC0KICBuaG9vZF9tYXJrZXJzJGRnZSAlPiUKICBwaXZvdF9sb25nZXIoY29scz1zdHJfc3Vic2V0KGNvbG5hbWVzKG5ob29kX21hcmtlcnMkZGdlKSwgImFkai5QLlZhbF8iKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHM9c3RyX3N1YnNldChjb2xuYW1lcyhuaG9vZF9tYXJrZXJzJGRnZSksICJsb2dGQ18iKSwgbmFtZXNfdG89J3NtcCcsIHZhbHVlc190bz0ibG9nRkMiKSAlPiUKICAgbXV0YXRlKG5hbWU9c3RyX3JlbW92ZShuYW1lLCAiYWRqLlAuVmFsXyIpLCBzbXA9c3RyX3JlbW92ZShzbXAsImxvZ0ZDXyIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHNtcD09bmFtZSkgJT4lCiAgZHBseXI6OmZpbHRlcihzbXA9PTEpICU+JQogIG11dGF0ZShsb2dGQ19kaXI9aWZlbHNlKGxvZ0ZDIDwgMCwgImRvd24iLCAndXAnKSkgJT4lCiAgZ3JvdXBfYnkobG9nRkNfZGlyKSAlPiUKICB0b3BfbihuPTUwLCAtbG9nMTAodmFsdWUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBkcGx5cjo6ZmlsdGVyKHZhbHVlIDwgMC4wMSAmIGFicyhsb2dGQykgPiAwLjAyKSAlPiUKICBwdWxsKEdlbmVJRCkgJT4lCiAgdW5pcXVlKCkKCgpuaG9vZF9tYXJrZXJzJGRnZSAlPiUKICBwaXZvdF9sb25nZXIoY29scz1zdHJfc3Vic2V0KGNvbG5hbWVzKG5ob29kX21hcmtlcnMkZGdlKSwgImFkai5QLlZhbF8iKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHM9c3RyX3N1YnNldChjb2xuYW1lcyhuaG9vZF9tYXJrZXJzJGRnZSksICJsb2dGQ18iKSwgbmFtZXNfdG89J3NtcCcsIHZhbHVlc190bz0ibG9nRkMiKSAlPiUKICBtdXRhdGUobmFtZT1zdHJfcmVtb3ZlKG5hbWUsICJhZGouUC5WYWxfIiksIHNtcD1zdHJfcmVtb3ZlKHNtcCwibG9nRkNfIikpICU+JQogIGRwbHlyOjpmaWx0ZXIoc21wPT1uYW1lKSAlPiUKICBtdXRhdGUoY29sb3I9aWZlbHNlKHZhbHVlPDAuMDUsIDEsIDApLAogICAgICAgICBsYWJlbD1pZmVsc2UoR2VuZUlEICVpbiUgbWFya2VyX2dlbmVzLCBHZW5lSUQsTkEpKSAlPiUKICBnZ3Bsb3QoYWVzKGxvZ0ZDLCAtbG9nMTAodmFsdWUpLCBjb2xvcj1jb2xvcikpICsKICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgZmFjZXRfd3JhcChuYW1lfi4sIHNjYWxlcz0iZnJlZSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoMC4wMSkpICsKICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWxhYmVsKSkKYGBgCmBgYHtyfQptYXJrZXJfZ2VuZXMgPC0gbmhvb2RfbWFya2VycyRkZ2UgJT4lCiAgZHBseXI6OmZpbHRlcihhZGouUC5WYWxfMSA8IDAuMDEpICU+JQogIHB1bGwoR2VuZUlEKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTE4LCBmaWcud2lkdGg9MTJ9CmxpdmVyX21pbG8gPC0gY2FsY05ob29kRXhwcmVzc2lvbihsaXZlcl9taWxvLCBzdWJzZXQucm93ID0gbWFya2VyX2dlbmVzKQoKcGxvdE5ob29kRXhwcmVzc2lvbkRBKGxpdmVyX21pbG8sIG1pbG9fcmVzLCBtYXJrZXJfZ2VuZXMsIGNsdXN0ZXJfZmVhdHVyZXMgPSBUUlVFLCBhbHBoYSA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgICBzY2FsZV90b18xID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5uaG9vZHMgPSBtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIgogICAgICAgICAgICAgICAgICAgICAgKQpgYGAKCgpDdXN0b21pemUgcGxvdHRpbmcgZm9yIHBhcGVyIGZpZ3VyZQoKYGBge3J9CnggPC0gbGl2ZXJfbWlsbwpkYS5yZXMgPC0gbWlsb19yZXMKCmNsdXN0ZXJfZmVhdHVyZXMgPSBUUlVFCmFscGhhID0gMC4wNQpzY2FsZV90b18xID0gVFJVRQpzdWJzZXQubmhvb2RzID0gbWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIKZmVhdHVyZXMgPC0gbWFya2VyX2dlbmVzCgpleHByX21hdCA8LSBuaG9vZEV4cHJlc3Npb24oeClbZmVhdHVyZXMsXQpjb2xuYW1lcyhleHByX21hdCkgPC0gMTpsZW5ndGgobmhvb2RzKHgpKQoKIyMgR2V0IG5ob29kIGV4cHJlc3Npb24gbWF0cml4CmlmICghaXMubnVsbChzdWJzZXQubmhvb2RzKSkgewogIGV4cHJfbWF0IDwtIGV4cHJfbWF0WyxzdWJzZXQubmhvb2RzLCBkcm9wPUZBTFNFXQp9CgppZiAoIWlzRkFMU0Uoc2NhbGVfdG9fMSkpIHsKICBleHByX21hdCA8LSB0KGFwcGx5KGV4cHJfbWF0LCAxLCBmdW5jdGlvbih4KSAoeCAtIG1pbih4KSkvKG1heCh4KS0gbWluKHgpKSkpCn0KCnJvd25hbWVzKGV4cHJfbWF0KSA8LSBzdWIocGF0dGVybiA9ICItIiwgcmVwbGFjZW1lbnQgPSAiLiIsIHJvd25hbWVzKGV4cHJfbWF0KSkgIyMgVG8gYXZvaWQgcHJvYmxlbXMgd2hlbiBjb252ZXJ0aW5nIHRvIGRhdGEuZnJhbWUKCnBsX2RmIDwtIGRhdGEuZnJhbWUodChleHByX21hdCkpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigiTmhvb2QiKSAlPiUKICBtdXRhdGUoTmhvb2Q9YXMuZG91YmxlKE5ob29kKSkgJT4lCiAgbGVmdF9qb2luKGRhLnJlcywgYnk9Ik5ob29kIikgJT4lCiAgbXV0YXRlKGxvZ0ZDX3Jhbms9cGVyY2VudF9yYW5rKGxvZ0ZDKSkgCgojIyBUb3AgcGxvdDogbmhvb2RzIHJhbmtlZCBieSBEQSBsb2cgRkMKcGxfdG9wIDwtIHBsX2RmICU+JQogIG11dGF0ZShpc19zaWduaWYgPSBpZmVsc2UoU3BhdGlhbEZEUiA8IGFscGhhLCBwYXN0ZTAoIlNwYXRpYWxGRFIgPCAiLCBhbHBoYSksIE5BKSkgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBsb2dGQykpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0yKSArCiAgZ2VvbV9wb2ludChzaXplPTAuMiwgY29sb3I9ImdyZXkiKSArCiAgZ2VvbV9wb2ludChkYXRhPS4lPiUgZmlsdGVyKCFpcy5uYShpc19zaWduaWYpKSwgYWVzKGNvbG9yPWlzX3NpZ25pZiksIHNpemU9MSkgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xNikgKwogIHlsYWIoIkRBIGxvZ0ZDIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9InJlZCIsIG5hbWU9IiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjAxLCAwKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCiMjIEJvdHRvbSBwbG90OiBnZW5lIGV4cHJlc3Npb24gaGVhdG1hcAppZiAoaXNUUlVFKGNsdXN0ZXJfZmVhdHVyZXMpKSB7CiAgcm93Lm9yZGVyIDwtIGhjbHVzdChkaXN0KGV4cHJfbWF0KSkkb3JkZXIgIyBjbHVzdGVyaW5nCiAgb3JkZXJlZF9mZWF0dXJlcyA8LSByb3duYW1lcyhleHByX21hdClbcm93Lm9yZGVyXQp9IGVsc2UgewogIG9yZGVyZWRfZmVhdHVyZXMgPC0gcm93bmFtZXMoZXhwcl9tYXQpCn0KCgpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTEwfQpoaWdobGlnaHRfZ2VuZXMgPC0gYygiUExWQVAiLCAiU09YMTQiLCAiVldBMSIsICJBQ0tSMSIsCiAgICAgICAgICAgICAgICAgICAgICJDTEVDNEciLCAiQ0xFQzRNIiwgIlNUQUIyIiwgIk1SQzEiLAogICAgICAgICAgICAgICAgICAgICAiQ0QxNCIsICJDQ0wyMSIsICJTT1gxNyIsICJXTlQyIiwgIlJTUE8zIiwgIkFJRjFMIiwKICAgICAgICAgICAgICAgICAgICAgIlBST1gxIiwgIlBEUE4iLCJDUEUiLCAiQ0QzMjAiKQoKIyAjIyBPcmRlcmluZyBmZWF0dXJlcyBieSBwZWFrIGluIGV4cHJlc3Npb24KIyBvcmRlcmVkX2ZlYXR1cmVzIDwtCiMgICBwbF9kZiAlPiUKIyAgIHBpdm90X2xvbmdlcihjb2xzPXJvd25hbWVzKGV4cHJfbWF0KSwgbmFtZXNfdG89J2ZlYXR1cmUnLCB2YWx1ZXNfdG89ImF2Z19leHByIikgJT4lCiMgICBncm91cF9ieShmZWF0dXJlKSAlPiUKIyAgIGFycmFuZ2UobG9nRkNfcmFuaykgJT4lCiMgICBtdXRhdGUoYXZnX2V4cHIgPSB6b286OnJvbGxtZWFuKGF2Z19leHByLDEwLCBmaWxsID0gTkEpKSAlPiUKIyAgIHN1bW1hcmlzZShtYXhfcG9pbnQ9bG9nRkNfcmFua1t3aGljaChhdmdfZXhwcj09bWF4KGF2Z19leHByLCBuYS5ybT1UUlVFKSldKSAlPiUKIyAgIGFycmFuZ2UobWF4X3BvaW50KSAlPiUKIyAgIHB1bGwoZmVhdHVyZSkKIyAgIAojICMjIE9yZGVyaW5nIGZlYXR1cmVzIGJ5IGZjIGluIG1hcmtlciB0ZXN0CiMgb3JkZXJlZF9mZWF0dXJlcyA8LSBuaG9vZF9tYXJrZXJzJGRnZSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIoYWRqLlAuVmFsXzEgPCAwLjAxKSAlPiUKIyAgIGFycmFuZ2UobG9nRkNfMSkgJT4lCiMgICB1bmlxdWUoKSAlPiUKIyAgIHB1bGwoR2VuZUlEKQoKcGxfYm90dG9tIDwtIHBsX2RmICU+JQogIHBpdm90X2xvbmdlcihjb2xzPXJvd25hbWVzKGV4cHJfbWF0KSwgbmFtZXNfdG89J2ZlYXR1cmUnLCB2YWx1ZXNfdG89ImF2Z19leHByIikgJT4lCiAgbXV0YXRlKGZlYXR1cmU9ZmFjdG9yKGZlYXR1cmUsIGxldmVscz1vcmRlcmVkX2ZlYXR1cmVzKSkgJT4lIAogIG11dGF0ZShsYWJlbD1pZmVsc2UoZmVhdHVyZSAlaW4lIGhpZ2hsaWdodF9nZW5lcywgYXMuY2hhcmFjdGVyKGZlYXR1cmUpLCBOQSkpICU+JQogIGdncGxvdChhZXMobG9nRkNfcmFuaywgZmVhdHVyZSwgZmlsbD1hdmdfZXhwcikpICsgCiAgZ2VvbV90aWxlKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0ibWFnbWEiLCBuYW1lPSJTY2FsZWQgTkhcbmV4cHJlc3Npb24iKSArCiAgeGxhYigiRW5kb3RoZWxpYWwgTmVpZ2hib3VyaG9vZHMiKSArIHlsYWIoIkRFIGdlbmVzIikgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAuMDEsIDApLAogICAgICAgICAgICAgICAgICAgICAjIGxpbWl0cyA9IGMoMCwgbWF4KHBsX2RmJGxvZ0ZDX3JhbmspICsgMC4yKQogICAgICAgICAgICAgICAgICAgICApICsKICBjb29yZF9jYXJ0ZXNpYW4oY2xpcD0ib2ZmIikgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhPS4gJT4lIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGxhYmVsKSkgJT4lIAogICAgICAgICAgICAgIGdyb3VwX2J5KGxhYmVsKSAlPiUKICAgICAgICAgICAgICBzdW1tYXJpc2UobG9nRkNfcmFuaz1tYXgobG9nRkNfcmFuayksIGF2Z19leHByPW1lYW4oYXZnX2V4cHIpLCBmZWF0dXJlPWRwbHlyOjpmaXJzdChmZWF0dXJlKSksCiAgICAgICAgICAgIGFlcyhsYWJlbD1sYWJlbCwgeD1sb2dGQ19yYW5rKSwgc2l6ZT00LCB4bGltID0gYyhtYXgocGxfZGYkbG9nRkNfcmFuaykgKyAwLjAxLCBtYXgocGxfZGYkbG9nRkNfcmFuaykgKyAwLjAyKSwKICAgICAgICAgICAgbWluLnNlZ21lbnQubGVuZ3RoID0gMCwgc2VlZD00MgogICAgICAgICAgICApICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE2KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuc3BhY2luZyA9IG1hcmdpbigyLCAyLCAyLCAyLCAiY20iKSwKICAgICAgICBsZWdlbmQubWFyZ2luPW1hcmdpbigwLDAsMCwwKSwKICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbj1tYXJnaW4oMTAsMTAsMTAsMTApCiAgICAgICAgKQoKIyMgQXNzZW1ibGUgcGxvdAoocGxfdG9wIC8gcGxfYm90dG9tKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsNCkpICsKICBnZ3NhdmUoIn4vbWlsb19vdXRwdXQvbGl2ZXJfREVHX2hlYXRtYXAucGRmIiwgd2lkdGg9OSwgaGVpZ2h0ID0gOSkKCmBgYAoKIyMjIyBRdWljayBHTyB0ZXJtIGFuYWx5c2lzCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZW5yaWNoUiIpCmxpYnJhcnkoZW5yaWNoUikKCmRicyA8LSBsaXN0RW5yaWNockRicygpCndlYnNpdGVMaXZlIDwtIFRSVUUKaWYgKGlzLm51bGwoZGJzKSkgd2Vic2l0ZUxpdmUgPC0gRkFMU0UKaWYgKHdlYnNpdGVMaXZlKSBoZWFkKGRicykKCmRicyA8LSBjKCJHT19Nb2xlY3VsYXJfRnVuY3Rpb25fMjAxNSIsICJHT19DZWxsdWxhcl9Db21wb25lbnRfMjAxNSIsICJHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAxNSIpCmdvX21hcmtlcl9nZW5lcyA8LSBlbnJpY2hyKG1hcmtlcl9nZW5lcywgZGJzLCApCmdvX2FsbF9nZW5lcyA8LSBlbnJpY2hyKGVuZG9faHZncywgZGJzKQoKcmVmX3Rlcm1zIDwtIGdvX2FsbF9nZW5lcyRHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAxNSRUZXJtW2dvX2FsbF9nZW5lcyRHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAxNSRBZGp1c3RlZC5QLnZhbHVlIDwgMC4wMV0KCmdvX21hcmtlcl9nZW5lcyRHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAxNVtnb19tYXJrZXJfZ2VuZXMkR09fQmlvbG9naWNhbF9Qcm9jZXNzXzIwMTUkQWRqdXN0ZWQuUC52YWx1ZSA8IDAuMDEsXSAlPiUKICBmaWx0ZXIoIVRlcm0gJWluJSByZWZfdGVybXMpICU+JQogIHRvcF9uKDMwLCAtbG9nMTAoQWRqdXN0ZWQuUC52YWx1ZSkpICU+JQogIG11dGF0ZShUZXJtPWZhY3RvcihUZXJtLCBsZXZlbHM9cmV2KHVuaXF1ZShUZXJtKSkpKSAlPiUKICBnZ3Bsb3QoYWVzKFRlcm0sIC1sb2cxMChBZGp1c3RlZC5QLnZhbHVlKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiR08gQklvbG9naWNhbCBGdW5jdGlvbiIpICsgeWxhYigiLWxvZzEwKEFkai4gcC12YWx1ZSkiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE0KSArCiAgZ2dzYXZlKCJ+L21pbG9fb3V0cHV0L2xpdmVyX2VuZG9ERUdfR09lbnJpY2gucGRmIiwgd2lkdGg9OSwgaGVpZ2h0ID0gNSkKYGBgCgoKTGV0J3MgY2hlY2sgdGhlIGdlbmVzIGlkZW50aWZpZWQgYXMgbWFya2VycyBmb3IgdGhlIGRpc2Vhc2Ugc3VidHlwZXMuIEFyZSB0aGV5IHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGJldHdlZW4gREEgbmVpZ2hib3VyaG9vZHM/IFllcyB0aGV5IGFyZSEKCmBgYHtyfQpkaXNlYXNlX2VuZG9fbWFya2VycyA8LSBjKCJBQ0tSMSIsICdDRDM0JywiVldBMSIpCgpkYXRhLmZyYW1lKG1hcmtlcnMkbmVnTG9nRkNfMikgJT4lCiAgZmlsdGVyKEZEUiA8IDAuMDUpICU+JQogIC5bZGlzZWFzZV9lbmRvX21hcmtlcnMsXQoKZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzEpICU+JQogIGZpbHRlcihGRFIgPCAwLjA1KSAlPiUKICAuW2Rpc2Vhc2VfZW5kb19tYXJrZXJzLF0KYGBgCgpWaXN1YWxpemUgc29tZSBvZiB0aGUgbWFya2VycyB0aGF0IGRpZmZlcmVudGlhdGUgREEgbmVpZ2hib3VyaG9vZHMsIGJ5IHBsb3R0aW5nIHRoZSBwZXJjZW50IG9mIGNlbGxzIGV4cHJlc3NpbmcgZWFjaCBnZW5lIGluIGEgbmhvb2QuCgpgYGB7cn0KIyMgRGVmaW5lIHBsb3R0aW5nIGZ1bmN0aW9ucwouY2FsY3VsYXRlX25ob29kX3BlcmNfZXhwcmVzc2lvbiA8LSBmdW5jdGlvbihtaWxvLCBuaG9vZHMsIGdlbmUpewogIGdlbmVfY250cyA8LSBjb3VudHMobWlsbylbZ2VuZSxdCiAgcGVyY19leHByIDwtIHNhcHBseShuaG9vZHMobWlsbylbbmhvb2RzXSwgZnVuY3Rpb24oeCkgc3VtKGdlbmVfY250c1t4XT4wKS9sZW5ndGgoeCkpCiAgcGVyY19leHByIDwtIHNldE5hbWVzKHBlcmNfZXhwciwgbmhvb2RzKQogIHJldHVybihwZXJjX2V4cHIpCiAgfQoKLnBsb3Rfbmhvb2RfZXhwcmVzc2lvbiA8LSBmdW5jdGlvbihtaWxvLCBuaG9vZHMsIGZlYXR1cmVzKXsKICBwZXJjX2V4cHJfbWF0IDwtIHNhcHBseShmZWF0dXJlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgLmNhbGN1bGF0ZV9uaG9vZF9wZXJjX2V4cHJlc3Npb24obWlsbywgbmhvb2RzLCB4KSkKICAKICBwbF9kZiA8LSBkYXRhLmZyYW1lKHBlcmNfZXhwcl9tYXQpICU+JQogICAgcm93bmFtZXNfdG9fY29sdW1uKCJOaG9vZCIpICU+JQogICAgbXV0YXRlKE5ob29kPWFzLmRvdWJsZShOaG9vZCkpICU+JQogICAgbGVmdF9qb2luKG1pbG9fcmVzKSAlPiUKICAgIG11dGF0ZShsb2dGQ19yYW5rPXJhbmsobG9nRkMpKSAKICAKICBwbF90b3AgPC0gcGxfZGYgJT4lCiAgICAgIG11dGF0ZShpc19zaWduaWYgPSBpZmVsc2UoU3BhdGlhbEZEUiA8IDAuMSwgIlNwYXRpYWxGRFIgPCAwLjEiLCBOQSkpICU+JQogICAgICBnZ3Bsb3QoYWVzKGxvZ0ZDX3JhbmssIGxvZ0ZDKSkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0yKSArCiAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjIpICsKICAgICAgZ2VvbV9wb2ludChkYXRhPS4lPiUgZmlsdGVyKCFpcy5uYShpc19zaWduaWYpKSwgYWVzKGNvbG9yPWlzX3NpZ25pZiksIHNpemU9MC41KSArCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSJyZWQiLCBuYW1lPSIiKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKICAgIAogIHBsX2JvdHRvbSA8LSBwbF9kZiAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzPWZlYXR1cmVzLCBuYW1lc190bz0nZmVhdHVyZScsIHZhbHVlc190bz0icGVyY19leHByZXNzZWQiKSAlPiUKICAgIG11dGF0ZShmZWF0dXJlPWZhY3RvcihmZWF0dXJlLCBsZXZlbHM9ZmVhdHVyZXMpKSAlPiUKICAgIGdncGxvdChhZXMobG9nRkNfcmFuaywgZmVhdHVyZSwgZmlsbD1wZXJjX2V4cHJlc3NlZCkpICsgCiAgICBnZW9tX3RpbGUoKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249Im1hZ21hIikgKwogICAgZ2diaW86OnRoZW1lX2NsZWFyKCkKICAKICAocGxfdG9wIC8gcGxfYm90dG9tKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMikpCn0KYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMn0KZW5kb19uaG9vZHMgPC0gZW5kb19yZXMgJT4lICBwdWxsKE5ob29kKQoKIyMgU2VsZWN0IGdlbmVzIGFuZCBzb3J0IGJ5IEFVQwpmZWF0c19uZWcyIDwtCiAgZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzIpICU+JSAKICB0b3Bfbig1MCwgLSBsb2cxMChGRFIpKSAlPiUKICBhcnJhbmdlKEFVQy5wb3NMb2dGQ18xKSAlPiUKICByb3duYW1lcygpCgoucGxvdF9uaG9vZF9leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG9fbmhvb2RzLCBmZWF0dXJlcz1mZWF0cykKYGBgCgpBcyBkZXNjcmliZWQgaW4gdGhlIHBhcGVyLCB3ZSBoYXZlIHRoYXQgZ2VuZXMgYXNzb2NpYXRlZCB3aXRoIGV4dHJhY2VsbHVsYXIgbWF0cml4IG9yZ2FuaXphdGlvbiAoZS5nLiBWSU0sICkgYXJlIG92ZXIgZXhwcmVzc2VkIAoKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9N30KIyMgU2VsZWN0IGdlbmVzIGFuZCBzb3J0IGJ5IEFVQwpmZWF0c19uZWcxIDwtCiAgZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzEpICU+JSAKICB0b3Bfbig1MCwgLSBsb2cxMChGRFIpKSAlPiUKICBhcnJhbmdlKEFVQy5wb3NMb2dGQ18xKSAlPiUKICByb3duYW1lcygpCgoucGxvdF9uaG9vZF9leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG9fbmhvb2RzLCBmZWF0dXJlcz1mZWF0cykKCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQpmZWF0c19uZWcxdnNOZWcyIDwtCiAgZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzEpICU+JSAKICB0b3Bfbig1MCwgLSBsb2cxMChGRFIpKSAlPiUKICBhcnJhbmdlKEFVQy5uZWdMb2dGQ18yKSAlPiUKICByb3duYW1lcygpCgoucGxvdF9uaG9vZF9leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG9fbmhvb2RzLCBmZWF0dXJlcz1mZWF0c19uZWcxdnNOZWcyKQpgYGAKCgo8IS0tIExvb2sganVzdCBhdCBFbmRvdGhlbGlhICg1KSB3aGVyZSB5b3UgaGF2ZSBib3RoIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSBmb2xkLWNoYW5nZXMgLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBlbmRvNV9uaG9vZHMgPC0gbWlsb19yZXMgJT4lICAtLT4KPCEtLSAgIGZpbHRlcihhbm5vdGF0aW9uX2luZGVwdGg9PSJFbmRvdGhlbGlhICg1KSIgJiBhbm5vdGF0aW9uX2luZGVwdGhfZnJhY3Rpb24gPiAwLjcpICU+JSAtLT4KPCEtLSAgIHB1bGwoTmhvb2QpIC0tPgoKPCEtLSBwZXJjX2V4cHJfbWF0IDwtIHNhcHBseShmZWF0dXJlcywgIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIC5jYWxjdWxhdGVfbmhvb2RfcGVyY19leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG81X25ob29kcywgeCkpIC0tPgoKPCEtLSBwbF9kZiA8LSBkYXRhLmZyYW1lKHBlcmNfZXhwcl9tYXQpICU+JSAtLT4KPCEtLSAgIHJvd25hbWVzX3RvX2NvbHVtbigiTmhvb2QiKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoTmhvb2Q9YXMuZG91YmxlKE5ob29kKSkgJT4lIC0tPgo8IS0tICAgbGVmdF9qb2luKG1pbG9fcmVzKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUobG9nRkNfcmFuaz1yYW5rKGxvZ0ZDKSkgIC0tPgoKPCEtLSBwbF90b3AgPC0gcGxfZGYgJT4lIC0tPgo8IS0tICAgICBtdXRhdGUoaXNfc2lnbmlmID0gaWZlbHNlKFNwYXRpYWxGRFIgPCAwLjEsICJTcGF0aWFsRkRSIDwgMC4xIiwgTkEpKSAlPiUgLS0+CjwhLS0gICAgIGdncGxvdChhZXMobG9nRkNfcmFuaywgbG9nRkMpKSArIC0tPgo8IS0tICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0yKSArIC0tPgo8IS0tICAgICBnZW9tX3BvaW50KHNpemU9MC4yKSArIC0tPgo8IS0tICAgICBnZW9tX3BvaW50KGRhdGE9LiU+JSBmaWx0ZXIoIWlzLm5hKGlzX3NpZ25pZikpLCBhZXMoY29sb3I9aXNfc2lnbmlmKSwgc2l6ZT0wLjUpICsgLS0+CjwhLS0gICAgIHRoZW1lX2J3KCkgKyAtLT4KPCEtLSAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0icmVkIiwgbmFtZT0iIikgKyAtLT4KPCEtLSAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSAtLT4KCjwhLS0gcGxfYm90dG9tIDwtIHBsX2RmICU+JSAtLT4KPCEtLSAgIHBpdm90X2xvbmdlcihjb2xzPWZlYXR1cmVzLCBuYW1lc190bz0nZmVhdHVyZScsIHZhbHVlc190bz0icGVyY19leHByZXNzZWQiKSAlPiUgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKGxvZ0ZDX3JhbmssIGZlYXR1cmUsIGZpbGw9cGVyY19leHByZXNzZWQpKSArICAtLT4KPCEtLSAgIGdlb21fdGlsZSgpICsgLS0+CjwhLS0gICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249Im1hZ21hIikgKyAtLT4KPCEtLSAgIHRoZW1lX2NsZWFyKCkgLS0+Cgo8IS0tIChwbF90b3AgLyBwbF9ib3R0b20pICsgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMSwyKSkgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBIb3cgdG8gZmluZCBhc3NvY2lhdGlvbiBkZSBub3ZvIGluIEVuZG8gNT8gLS0+Cgo8IS0tIGBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fSAtLT4KPCEtLSAjIyBGaW5kIG1vc3QgaGlnaGx5IHZhcmlhYmxlIGdlbmVzIGluIHRoaXMgY2x1c3RlciAtLT4KPCEtLSBlbmRvNV9taWxvIDwtIGxpdmVyX21pbG9bLHdoaWNoKGNvbERhdGEobGl2ZXJfbWlsbylbWyJhbm5vdGF0aW9uX2luZGVwdGgiXV09PSJFbmRvdGhlbGlhICg1KSIpXSAtLT4KPCEtLSBkZWNfZW5kbzUgPC0gbW9kZWxHZW5lVmFyKGVuZG81X21pbG8pIC0tPgo8IS0tIGVuZG81X2h2Z3MgPC0gZ2V0VG9wSFZHcyhkZWNfZW5kbzUsIG49MTAwMCkgLS0+Cgo8IS0tIHBlcmNfZXhwcl9tYXQgPC0gc2FwcGx5KGVuZG81X2h2Z3MsIGZ1bmN0aW9uKHgpIC5jYWxjdWxhdGVfbmhvb2RfcGVyY19leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG81X25ob29kcywgeCkpIC0tPgoKPCEtLSBtaWxvX3Jlc19lbmRvNSA8LSBtaWxvX3Jlc1t3aGljaChtaWxvX3JlcyROaG9vZCAlaW4lIGVuZG81X25ob29kcyksXSAtLT4KCjwhLS0gZmNfY29yIDwtIGFwcGx5KHBlcmNfZXhwcl9tYXQsIDIsIGZ1bmN0aW9uKHgpIEhtaXNjOjpyY29ycih4LCBtaWxvX3Jlc19lbmRvNSRsb2dGQykkclsxLDJdKSAtLT4KPCEtLSBmY19jb3JfcHZhbCA8LSBhcHBseShwZXJjX2V4cHJfbWF0LCAyLCBmdW5jdGlvbih4KSBIbWlzYzo6cmNvcnIoeCwgbWlsb19yZXNfZW5kbzUkbG9nRkMpJFBbMSwyXSkgLS0+Cgo8IS0tIGNvcl9mZWF0cyA8LSBuYW1lcyh3aGljaChhYnMoZmNfY29yKSA+IDAuNiAmIGFicyhmY19jb3JfcHZhbCkgPCAwLjA1KSkgLS0+CjwhLS0gY29yX2ZlYXRzX29yZGVyZWQgPC0gY29yX2ZlYXRzW29yZGVyKGZjX2Nvcltjb3JfZmVhdHNdKV0gLS0+Cgo8IS0tIHBsX2RmIDwtIGRhdGEuZnJhbWUocGVyY19leHByX21hdFssY29yX2ZlYXRzXSkgJT4lIC0tPgo8IS0tICAgcm93bmFtZXNfdG9fY29sdW1uKCJOaG9vZCIpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShOaG9vZD1hcy5kb3VibGUoTmhvb2QpKSAlPiUgLS0+CjwhLS0gICBsZWZ0X2pvaW4obWlsb19yZXMpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShsb2dGQ19yYW5rPXJhbmsobG9nRkMpKSAgLS0+Cgo8IS0tIHBsX3RvcCA8LSBwbF9kZiAlPiUgLS0+CjwhLS0gICAgIG11dGF0ZShpc19zaWduaWYgPSBpZmVsc2UoU3BhdGlhbEZEUiA8IDAuMSwgIlNwYXRpYWxGRFIgPCAwLjEiLCBOQSkpICU+JSAtLT4KPCEtLSAgICAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBsb2dGQykpICsgLS0+CjwhLS0gICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPTIpICsgLS0+CjwhLS0gICAgIGdlb21fcG9pbnQoc2l6ZT0wLjIpICsgLS0+CjwhLS0gICAgIGdlb21fcG9pbnQoZGF0YT0uJT4lIGZpbHRlcighaXMubmEoaXNfc2lnbmlmKSksIGFlcyhjb2xvcj1pc19zaWduaWYpLCBzaXplPTAuNSkgKyAtLT4KPCEtLSAgICAgdGhlbWVfYncoKSArIC0tPgo8IS0tICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSJyZWQiLCBuYW1lPSIiKSArIC0tPgo8IS0tICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpIC0tPgoKPCEtLSBwbF9ib3R0b20gPC0gcGxfZGYgJT4lIC0tPgo8IS0tICAgcGl2b3RfbG9uZ2VyKGNvbHM9c3RyX3JlcGxhY2UoY29yX2ZlYXRzX29yZGVyZWQsICItIiwgIi4iKSwgbmFtZXNfdG89J2ZlYXR1cmUnLCB2YWx1ZXNfdG89InBlcmNfZXhwcmVzc2VkIikgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGZlYXR1cmU9ZmFjdG9yKGZlYXR1cmUsIGxldmVscz1zdHJfcmVwbGFjZShjb3JfZmVhdHNfb3JkZXJlZCwgIi0iLCAiLiIpKSkgJT4lIC0tPgo8IS0tICAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBmZWF0dXJlLCBmaWxsPXBlcmNfZXhwcmVzc2VkKSkgKyAgLS0+CjwhLS0gICBnZW9tX3RpbGUoKSArIC0tPgo8IS0tICAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uPSJtYWdtYSIpICsgLS0+CjwhLS0gICB0aGVtZV9jbGVhcigpIC0tPgoKPCEtLSAocGxfdG9wIC8gcGxfYm90dG9tKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMikpIC0tPgo8IS0tIGBgYCAtLT4KCgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gIyMgUnVuIGNvbW1vbiBQQ0EgLS0+CjwhLS0gbWVyZ2VkX2NudHMgPC0gY2JpbmQobmhvb2RFeHByZXNzaW9uKGVuZG9fbWlsbyksIGxvZ2NvdW50cyhlbmRvX21pbG8pW2h2Z3MsXSkgLS0+CjwhLS0gbWVyZ2VkX2NudHNfc2NhbGVkIDwtIHQoc2NhbGUodChtZXJnZWRfY250cykpKSAtLT4KPCEtLSBtZXJnZWRfcGNhIDwtIEJpb2NTaW5ndWxhcjo6cnVuUENBKHQobWVyZ2VkX2NudHNfc2NhbGVkKSwgcmFuaz0zMCwgY2VudGVyPUZBTFNFKSAtLT4KPCEtLSBwY2FfbWF0IDwtIHJiaW5kKG1lcmdlZF9wY2EkeFsobmNvbChlbmRvX21pbG8pKzEpOihuY29sKGVuZG9fbWlsbykrKGxlbmd0aChuaG9vZHMoZW5kb19taWxvKSkpKSxdLCBtZXJnZWRfcGNhJHhbY29sbmFtZXMoZW5kb19taWxvKSxdKSAtLT4KPCEtLSAjIyBBZGQgdG8gc2xvdCBuaG9vZHNSZWR1Y2VkRGltIC0tPgo8IS0tIG5ob29kUmVkdWNlZERpbShlbmRvX21pbG8sICJQQ0EiKSA8LSBwY2FfbWF0IC0tPgoKPCEtLSAjIyBSdW4gVU1BUCBvbiBqb2ludCBQQ0EgLS0+CjwhLS0gdW1hcF9vdXQgPC0gdXdvdDo6dW1hcChuaG9vZFJlZHVjZWREaW0oZW5kb19taWxvLCAiUENBIiksIG5fbmVpZ2hib3JzID0gMjAsIG5fY29tcG9uZW50cyA9IDIsIHNjYWxlPUZBTFNFKSAtLT4KPCEtLSBjb2xuYW1lcyh1bWFwX291dCkgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpIC0tPgo8IS0tIG5ob29kUmVkdWNlZERpbShlbmRvX21pbG8sICJVTUFQIikgPC0gdW1hcF9vdXQgLS0+Cgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIHNwbGl0X2J5PU5VTEwgLS0+CjwhLS0gIyMgSm9pbiB0ZXN0IHJlc3VsdHMgYW5kIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbnMgLS0+CjwhLS0gcmRpbV9kZiA8LSBkYXRhLmZyYW1lKG5ob29kUmVkdWNlZERpbShlbmRvX21pbG8sICJVTUFQIilbLGMoMSwyKV0pIC0tPgo8IS0tIGNvbG5hbWVzKHJkaW1fZGYpIDwtIGMoJ1gnLCdZJykgLS0+Cgo8IS0tIG5fbmhvb2RzIDwtIGxlbmd0aChuaG9vZHMoZW5kb19taWxvKSkgLS0+CjwhLS0gcmRpbV9kZlssIk5ob29kIl0gPC0gaWZlbHNlKDE6bnJvdyhyZGltX2RmKSAlaW4lIGMoMTpuX25ob29kcyksIGMoMTpuX25ob29kcyksIE5BKSAtLT4KPCEtLSB2aXpfZGYgIDwtIGxlZnRfam9pbihyZGltX2RmLCBtaWxvX3Jlc1t3aGljaChtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIiksXSwgYnk9Ik5ob29kIikgLS0+CjwhLS0gdml6X2RmW1sibmhJbmRleCJdXSA8LSB1bmxpc3QoaWZlbHNlKCFpcy5uYSh2aXpfZGYkTmhvb2QpLCBuaG9vZEluZGV4KGVuZG9fbWlsbylbdml6X2RmJE5ob29kXSxOQSkpIC0tPgo8IS0tIHZpel9kZltpcy5uYSh2aXpfZGZbIm5oSW5kZXgiXSksJ25oSW5kZXgnXSA8LSAxOm5jb2woZW5kb19taWxvKSAjIEFkZCBpbmRleCBhbHNvIHRvIHNpbmdsZS1jZWxscyAtLT4KCjwhLS0gaWYgKCFpcy5udWxsKHNwbGl0X2J5KSl7IC0tPgo8IS0tICAgc3BsaXRfZGYgPC0gZGF0YS5mcmFtZShzcGxpdF9ieT1jb2xEYXRhKGVuZG9fbWlsbylbLHNwbGl0X2J5XSkgLS0+CjwhLS0gICBzcGxpdF9kZlssIm5oSW5kZXgiXSA8LSAxOm5yb3coc3BsaXRfZGYpIC0tPgo8IS0tICAgdml6X2RmICA8LSBsZWZ0X2pvaW4odml6X2RmLCBzcGxpdF9kZiwgYnk9Im5oSW5kZXgiKSAtLT4KPCEtLSB9IC0tPgoKPCEtLSBmaWx0ZXJfYWxwaGE9MC4xIC0tPgo8IS0tICMjIEZpbHRlciBzaWduaWZpY2FudCBEQSBuaG9vZHMgLS0+CjwhLS0gaWYgKCFpcy5udWxsKGZpbHRlcl9hbHBoYSkpIHsgLS0+CjwhLS0gICBpZiAoZmlsdGVyX2FscGhhID4gMCkgeyAtLT4KPCEtLSAgICAgdml6X2RmIDwtIG11dGF0ZSh2aXpfZGYsIGxvZ0ZDID0gaWZlbHNlKFNwYXRpYWxGRFIgPiBmaWx0ZXJfYWxwaGEsIE5BLCBsb2dGQykpIC0tPgo8IS0tICAgfSAtLT4KPCEtLSB9IC0tPgoKPCEtLSAjIyBQbG90IC0tPgo8IS0tIHB0X3NpemU9MSAtLT4KPCEtLSBuaG9vZF9yZWR1Y2VkX2RpbXM9IlVNQVAiIC0tPgo8IS0tIGNvbXBvbmVudHM9YygxLDIpIC0tPgo8IS0tICAgcGwgPC0gLS0+CjwhLS0gICAgIGdncGxvdChkYXRhID0gYXJyYW5nZSh2aXpfZGYsIGFicyhsb2dGQykpLCAtLT4KPCEtLSAgICAgICAgICAgIGFlcyhYLCBZKSkgKyAtLT4KPCEtLSAgICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSAnJyksIHNpemUgPSBwdF9zaXplIC8gMywgYWxwaGEgPSAwLjUpICsgLS0+CjwhLS0gICAgIGdlb21fcG9pbnQoIC0tPgo8IS0tICAgICAgIGRhdGEgPSAuICU+JSBmaWx0ZXIoIWlzLm5hKFNwYXRpYWxGRFIpKSwgLS0+CjwhLS0gICAgICAgYWVzKGZpbGwgPSBsb2dGQyksIC0tPgo8IS0tICAgICAgIHNpemUgPSBwdF9zaXplLCAtLT4KPCEtLSAgICAgICBzdHJva2UgPSAwLjEsIC0tPgo8IS0tICAgICAgICMgY29sb3VyPSJibGFjayIsIC0tPgo8IS0tICAgICAgIHNoYXBlID0gMjEgLS0+CjwhLS0gICAgICkgKyAtLT4KPCEtLSAgICAgc2NhbGVfZmlsbF9ncmFkaWVudDIoIC0tPgo8IS0tICAgICAgIG1pZHBvaW50ID0gMCwgLS0+CjwhLS0gICAgICAgaGlnaCA9ICJyZWQiLCAtLT4KPCEtLSAgICAgICBsb3cgPSAiYmx1ZSIsIC0tPgo8IS0tICAgICAgIG5hbWUgPSAibG9nLUZDIiAtLT4KPCEtLSAgICAgKSArIC0tPgo8IS0tICAgICB4bGFiKHBhc3RlKG5ob29kX3JlZHVjZWRfZGltcywgY29tcG9uZW50c1sxXSwgc2VwPSJfIikpICsgLS0+CjwhLS0gICAgIHlsYWIocGFzdGUobmhvb2RfcmVkdWNlZF9kaW1zLCBjb21wb25lbnRzWzJdLCBzZXA9Il8iKSkgLS0+Cgo8IS0tICAgaWYgKCFpcy5udWxsKHNwbGl0X2J5KSkgeyAtLT4KPCEtLSAgICAgcGwgPC0gcGwgKyBmYWNldF93cmFwKHNwbGl0X2J5fi4pIC0tPgo8IS0tICAgfSAtLT4KPCEtLSAgIGlmICghaXMubnVsbChmaWx0ZXJfYWxwaGEpKSB7IC0tPgo8IS0tICAgICBwbCA8LSBwbCArIC0tPgo8IS0tICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAnZ3JleScsIGxhYmVsID0gcGFzdGUoIlNwYXRpYWxGRFIgPiIsIHJvdW5kKGZpbHRlcl9hbHBoYSwgMikpKSArIC0tPgo8IS0tICAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQoIC0tPgo8IS0tICAgICAgICAgJycsIC0tPgo8IS0tICAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdCggLS0+CjwhLS0gICAgICAgICAgIHNoYXBlID0gMjEsIC0tPgo8IS0tICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siLCAtLT4KPCEtLSAgICAgICAgICAgZmlsbCA9ICJncmV5NTAiLCAtLT4KPCEtLSAgICAgICAgICAgc2l6ZSA9IHB0X3NpemUsIC0tPgo8IS0tICAgICAgICAgICBhbHBoYSA9IDEsIC0tPgo8IS0tICAgICAgICAgICBzdHJva2UgPSAwLjEgLS0+CjwhLS0gICAgICAgICApIC0tPgo8IS0tICAgICAgICkpIC0tPgo8IS0tICAgfSBlbHNlIHsgLS0+CjwhLS0gICAgIHBsIDwtIHBsICsgLS0+CjwhLS0gICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9ICdncmV5JykgKyAtLT4KPCEtLSAgICAgICBndWlkZXMoY29sb3I9Im5vbmUiKSAtLT4KPCEtLSAgIH0gLS0+Cgo8IS0tICAgcGwgPC0gcGwgKyAtLT4KPCEtLSAgICAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxNikgKyAtLT4KPCEtLSAgICAgdGhlbWUoIC0tPgo8IS0tICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIC0tPgo8IS0tICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgLS0+CjwhLS0gICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkgLS0+CjwhLS0gICAgICkgLS0+CjwhLS0gcGwgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gZW5kb19taWxvIDwtIHNjYXRlcjo6cnVuUENBKGVuZG9fbWlsbywgc3Vic2V0X3Jvdz1odmdzKSAtLT4KPCEtLSBgYGAgLS0+CgoKCjwhLS0gLS0tIC0tPgo8IS0tICMjIE9sZCAoYmVmb3JlIEkgZ290IGRhdGFzZXQgZnJvbSBhdXRob3JzKSAtLT4KCjwhLS0gVXNpbmcgZGF0YSBmcm9tIFtSYW1hY2hhbmRyYW4gZXQgYWwuIDIwMTldKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTg2LTAxOS0xNjMxLTMjU2VjMSkgKEdFTyBhY2Nlc3NpaW9uOiBHU0UxMzYxMDMpLiAgLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBodW1hbl9maWxlcyA8LSBsaXN0LmZpbGVzKCJ+L0Rvd25sb2Fkcy9HU0UxMzYxMDNfUkFXIiwgcGF0dGVybj0iR1NNNDA0MTEuLl9oZWFsdGh5fGNpcnJob3RpYyIsIGZ1bGwubmFtZXMgPSBUUlVFKSAgLS0+Cgo8IS0tIHByZWZpeGVzIDwtIHN0cl9yZW1vdmUoaHVtYW5fZmlsZXMsICJiYXJjb2Rlcy50c3YuZ3p8Z2VuZXMudHN2Lmd6fG1hdHJpeC5tdHguZ3oiKSAlPiUgLS0+CjwhLS0gICAjIHN0cl9yZW1vdmUoIi4rLyIpICU+JSAtLT4KPCEtLSAgIHVuaXF1ZSgpICAtLT4KCjwhLS0gc2NlX2xzIDwtIGxhcHBseShwcmVmaXhlcywgZnVuY3Rpb24oeCkgcmVhZDEweENvdW50cyh4LCB0eXBlPSJwcmVmaXgiKSkgLS0+CjwhLS0gbGl2ZXJfc2NlIDwtIHB1cnJyOjpyZWR1Y2Uoc2NlX2xzLCBjYmluZCkgLS0+Cgo8IS0tICMjIE1ha2UgY29sRGF0YSBpbmZvIC0tPgo8IS0tIG5ld19jb2xkYXRhIDwtIGNvbERhdGEobGl2ZXJfc2NlKSAlPiUgLS0+CjwhLS0gICBkYXRhLmZyYW1lKCkgJT4lIC0tPgo8IS0tICAgbXV0YXRlKFNhbXBsZT1zdHJfcmVtb3ZlKFNhbXBsZSwgIi4rLyIpICU+JSBzdHJfcmVtb3ZlKCJfJCIpKSAlPiUgLS0+CjwhLS0gICBzZXBhcmF0ZShTYW1wbGUsIGludG89YygiY29sMSIsICJQYXRpZW50IiwgIlNvcnQiKSwgc2VwID0gIl8iLCByZW1vdmU9RkFMU0UpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoQ29uZGl0aW9uPXN0cl9yZW1vdmUoUGF0aWVudCwgIi4kIikpICU+JSAtLT4KPCEtLSAgIHNlbGVjdCgtY29sMSkgJT4lIC0tPgo8IS0tICAgbXV0YXRlKENlbGxfaWQgPSBzdHJfYyhTYW1wbGUsICJfIixCYXJjb2RlKSkgJT4lIC0tPgo8IS0tICAgY29sdW1uX3RvX3Jvd25hbWVzKCJDZWxsX2lkIikgLS0+Cgo8IS0tIGNvbG5hbWVzKGxpdmVyX3NjZSkgPC0gcm93bmFtZXMobmV3X2NvbGRhdGEpIC0tPgo8IS0tIGNvbERhdGEobGl2ZXJfc2NlKSA8LSBEYXRhRnJhbWUobmV3X2NvbGRhdGEpIC0tPgoKPCEtLSAjIHNhdmVSRFMobGl2ZXJfc2NlLCAifi9HU0UxMzYxMDNfU2luZ2xlQ2VsbEV4cGVyaW1lbnQuUkRTIikgLS0+CjwhLS0gYGBgIC0tPgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBsaXZlcl9zY2UgPC0gcmVhZFJEUygifi9HU0UxMzYxMDNfU2luZ2xlQ2VsbEV4cGVyaW1lbnQuUkRTIikgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBRQyBtZXRyaWNzIHNob3cgdGhhdCB0aGUgb3V0bGllciBjZWxscyBhcmUgYWxyZWFkeSBmaWx0ZXJlZCAoZm9sbG93aW5nIFt0aGlzXShodHRwczovL29zY2EuYmlvY29uZHVjdG9yLm9yZy9vdmVydmlldy5odG1sI2RhdGEtcHJvY2Vzc2luZy1hbmQtZG93bnN0cmVhbS1hbmFseXNpcykpIC0tPgoKPCEtLSBgYGB7ciwgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9OH0gLS0+CjwhLS0gIyBpcy5taXRvIDwtIGdyZXBsKCJeTVQtIiwgcm93bmFtZXMobGl2ZXJfc2NlKSkgLS0+CjwhLS0gcWNzdGF0cyA8LSBwZXJDZWxsUUNNZXRyaWNzKGxpdmVyX3NjZSkgLS0+Cgo8IS0tIGNvbERhdGEobGl2ZXJfc2NlKSA8LSBjYmluZChjb2xEYXRhKGxpdmVyX3NjZSksIHFjc3RhdHMpIC0tPgoKPCEtLSBwbG90Q29sRGF0YShsaXZlcl9zY2UsIHg9IlNhbXBsZSIsIHkgPSAidG90YWwiLCBvdGhlcl9maWVsZHMgPSAiQ29uZGl0aW9uIikgKyAtLT4KPCEtLSAgIHNjYWxlX3lfbG9nMTAoKSArIC0tPgo8IS0tICAgZmFjZXRfd3JhcCh+Q29uZGl0aW9uLCBzY2FsZXMgPSAiZnJlZSIpICsgLS0+CjwhLS0gICBnZ3RpdGxlKCJ0b3RhbCBjb3VudHMiKSAgLS0+Cgo8IS0tIHBsb3RDb2xEYXRhKGxpdmVyX3NjZSwgeD0iU2FtcGxlIiwgeSA9ICJkZXRlY3RlZCIsIG90aGVyX2ZpZWxkcyA9ICJDb25kaXRpb24iKSArIC0tPgo8IS0tICAgZmFjZXRfd3JhcCh+Q29uZGl0aW9uLCBzY2FsZXMgPSAiZnJlZSIpICsgLS0+CjwhLS0gICBnZ3RpdGxlKCJEZXRlY3RlZCBnZW5lcyIpICAtLT4KCjwhLS0gYGBgIC0tPgoKPCEtLSAjIyMgTm9ybWFsaXphdGlvbiAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIGxpYl9zZiA8LSBsaWJyYXJ5U2l6ZUZhY3RvcnMobGl2ZXJfc2NlKSAtLT4KPCEtLSBoaXN0KGxvZzEwKGxpYl9zZiksIHhsYWI9IkxvZzEwW1NpemUgZmFjdG9yXSIsIGNvbD0nZ3JleTgwJykgLS0+CjwhLS0gYGBgIC0tPgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBzZXQuc2VlZCgxMDApIC0tPgo8IS0tIGxpdmVyX3NjZSA8LSBsb2dOb3JtQ291bnRzKGxpdmVyX3NjZSkgLS0+CjwhLS0gYXNzYXlOYW1lcyhsaXZlcl9zY2UpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gIyMjIEZlYXR1cmUgc2VsZWN0aW9uIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gbGlicmFyeShzY3JhbikgLS0+CjwhLS0gZGVjX2xpdmVyIDwtIG1vZGVsR2VuZVZhcihsaXZlcl9zY2UpIC0tPgoKPCEtLSAjIFZpc3VhbGl6aW5nIHRoZSBmaXQ6IC0tPgo8IS0tIGZpdF9saXZlciA8LSBtZXRhZGF0YShkZWNfbGl2ZXIpIC0tPgo8IS0tIHBsb3QoZml0X2xpdmVyJG1lYW4sIGZpdF9saXZlciR2YXIsIHhsYWI9Ik1lYW4gb2YgbG9nLWV4cHJlc3Npb24iLCAtLT4KPCEtLSAgICAgeWxhYj0iVmFyaWFuY2Ugb2YgbG9nLWV4cHJlc3Npb24iKSAtLT4KCjwhLS0gaHZncyA8LSBnZXRUb3BIVkdzKGRlY19saXZlciwgbj0zMDAwKSAtLT4KPCEtLSBgYGAgLS0+CgoKCjwhLS0gIyMjIERpbSByZWR1Y3Rpb24gLS0+Cgo8IS0tIGBgYHtyLCBmaWcuaGVpZ2h0PTE0LCBmaWcud2lkdGg9MTR9IC0tPgo8IS0tIGxpdmVyX3NjZSA8LSBzY2F0ZXI6OnJ1blBDQShsaXZlcl9zY2UsIHN1YnNldF9yb3c9aHZncywgbmNvbXBvbmVudHM9MzApIC0tPgo8IS0tIHJlZHVjZWREaW0obGl2ZXJfc2NlLCAiUENBIikgPC0gcmVkdWNlZERpbShsaXZlcl9zY2UsICJQQ0EiKVssMToxMV0gLS0+CjwhLS0gcGxvdFBDQShsaXZlcl9zY2UsIGNvbG91cl9ieT0iQ29uZGl0aW9uIiwgbmNvbXBvbmVudHM9MykgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0gLS0+CjwhLS0gbGl2ZXJfc2NlIDwtIHJ1blVNQVAobGl2ZXJfc2NlLCBkaW1yZWQ9IlBDQSIsIG5jb21wb25lbnRzPTIpIC0tPgoKPCEtLSBzY2F0ZXI6OnBsb3RVTUFQKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJDb25kaXRpb24iLCBwb2ludF9hbHBoYT0xLCAgcG9pbnRfc2l6ZT0wLjgpICAtLT4KPCEtLSBzY2F0ZXI6OnBsb3RVTUFQKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJTb3J0IiwgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUpIC0tPgo8IS0tIHNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9IlBhdGllbnQiLCBwb2ludF9hbHBoYT0wLjMsICBwb2ludF9zaXplPTAuNSkgLS0+CjwhLS0gYGBgIC0tPgo8IS0tIGBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9IC0tPgo8IS0tIHJvd25hbWVzKGxpdmVyX3NjZSkgPC0gcm93RGF0YShsaXZlcl9zY2UpJFN5bWJvbCAtLT4KPCEtLSBzY2F0ZXI6OnBsb3RVTUFQKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJDRDNEIiwgcG9pbnRfYWxwaGE9MC4zLCBwb2ludF9zaXplPTAuNSkgLS0+CjwhLS0gYGBgIC0tPgoKCgo=